[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea\n.DS_Store\n/build\n/captures\n.externalNativeBuild"
  },
  {
    "path": "README.md",
    "content": "# oksharedpref\n\n```\n通过注解生成SharedPreferences实现的工具。解决安卓SharedPreferences多进程数据访问不一致的问题。\n```\n\n## 简介\n1. 让你告别手写包装代码管理SharedPreferences，通过注解的方式定义SharedPreferences包装类，使你可以方便的通过get/set方法操作SharedPreferences。\n2. 现在看来，安卓官方基本放弃了解决SharedPreferences跨进程访问不一致这一问题了，跨进程访问数据官方更加推荐ContentProvider。\n3. OkSharedPrefs将SharedPreferences和ContentProvider结合起来，让你使用SharedPreferences更加方便，并且通过ContentProvider交换数据，解决了跨进程数据访问不一致的问题。\n4. 底层仍然使用系统SharedPreferences实现，所以你的应用之前没有使用oksharedprefs，你可以很方便的移植，在新版本中加入这个库，已安装用户的原有数据不会有任何影响。\n\n## 安装\n\n```groovy\nallprojects {\n\t\trepositories {\n\t\t\tmaven { url 'https://jitpack.io' }\n\t\t}\n\t}\n\ndependencies {\n    compile 'com.github.sevenshal.oksharedprefs:api:1.0.1'\n    annotationProcessor 'com.github.sevenshal.oksharedprefs:processor:1.0.1'\n}\n```\n\n## 用法\n\n定一个interface类并且如下所示添加注解：\n\n```java\n\n@SharedPreference(value = \"Msg\", implSharedPreference = false, preferenceName = \"msg\", multiProcess = false)\npublic interface IMsg {\n\n    @DefaultValue(value = \"null\", createDefaultGetter = false)\n    String USERID = \"userId\";\n\n    @Type(PreferenceType.STRING_SET)\n    @DefaultValue(value = \"null\", createDefaultGetter = false)\n    String TOKEN = \"token\";\n\n    @Type(PreferenceType.LONG)\n    @DefaultValue(value = \"0\", createDefaultGetter = false)\n    String DEVICE_ID = \"deviceId\";\n\n    @Type(PreferenceType.BOOLEAN)\n    @DefaultValue(value = \"false\", createDefaultGetter = false)\n    String LOGIN = \"hasAuth\";\n\n    String NICK_NAME = \"nickName\";\n\n}\n```\n\n然后就可以直接使用生成的包装类了：\n\n``` java\n\n    MsgPrefs msgPrefs = MsgPrefs.defaultInstance(this);\n    long deviceId = msgPrefs.getDeviceId();\n    String userId = msgPrefs.getUserid();\n    boolean login = msgPrefs.isLogin();\n    String nickName= msgPrefs.getNickName(\"未命名\");\n    \n    msgPrefs.prefs().registerOnSharedPreferenceChangeListener(this);\n\n    Set set = new HashSet<String>();\n    set.add(\"a\");\n    set.add(\"b\");\n    msgPrefs.edit().setDeviceId(111).setLogin(true).setUserid(\"userid\").setToken(set).apply();\n\n```\n\n## 说明\n生成的类的名称通过 @SharedPreference 的 value属性定义。生成的类名称为 value+Prefs，比如\n\n@SharedPreference(value = \"Msg\") 将生成 MsgPrefs 类。\n\n如果你不希望以Prefs结尾，可以通过preferencesSuffix属性修改。\n\n@SharedPreference(value = \"Msg\", preferencesSuffix = \"Preferences\") 将生成 MsgPreferences类。\n\nOkSharedPrefs生成的包装类默认实现了SharedPreferences接口，\n这在key值通过变量方式存取时很方便，如果不希望生成的类实现SharedPreferences接口，\n可以通过将 implSharedPreference 设置为 false，关闭该功能。此种情况下，可以通过生成的类的prefs()获取SharedPreferences接口实例。\n\n默认的SharedPreferences文件名为default_preferences，你可以通过 preferenceName 修改。\n\n**默认生成的包装类不支持跨进程，但是可以通过将 multiProcess 设置为true打开该功能，默认关闭该功能是出于性能考虑，减少生成不必要的代码。**\n\n生成的包装类是单例模式的，因为安卓底层SharedPreferences也是全局单实例的，所以不会单例模式并不会带来性能问题。\n考虑到在插件化系统中Context可能会做隔离的使用场景，你仍然可以通过 new MsgPrefs(context)的方式来使用。\n甚至可以new MsgPrefs(context,name)来通过相同结构的包装类管理不同的属性文件，这对那种多用户数据管理的app很有用。\n\n所有属性默认类型是String类型，通过为interface的属性添加\n@Type(PreferenceType.LONG)\n来修改类型。支持完整的SharedPreferences数据类型。\n\n通过 @DefaultValue(value = \"null\", createDefaultGetter = false) 可以设置默认值，以及是否生成默认值取值方法。\ncreateDefaultGetter的取值意义在于你是希望通过 msgPrefs.getNickName(\"自定义默认值\") 还是 msgPrefs.getNickName() 获取数据。如果你在编码期间不确定默认值是什么，那需要将createDefaultGetter设为true。\n\n"
  },
  {
    "path": "annotations/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "annotations/build.gradle",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nbuildscript {\n    repositories {\n        mavenLocal()\n//        mavenCentral()\n    }\n}\n\napply plugin: 'java'\napply plugin: 'maven'\n//apply plugin: 'signing'\n\ncompileJava {\n    sourceCompatibility = 1.6\n    targetCompatibility = 1.7\n}\n\narchivesBaseName = \"annotations\"\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.google.android:android:4.1.1.4'\n}\n\ntask javadocJar(type: Jar) {\n    classifier = 'javadoc'\n    from javadoc\n}\n\ntask sourcesJar(type: Jar) {\n    classifier = 'sources'\n    from sourceSets.main.allSource\n}\n\nartifacts {\n    archives javadocJar, sourcesJar\n}\n\n//signing {\n//    sign configurations.archives\n//}\n\ndef ossrhUsername = System.properties['ossrhUsername']\ndef ossrhPassword = System.properties['ossrhPassword']\n\nuploadArchives {\n    repositories {\n        mavenDeployer {\n\n\n            repository(url: mavenLocal().getUrl())\n\n\n//            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n//\n//            repository(url: \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\") {\n//                authentication(userName: ossrhUsername, password: ossrhPassword)\n//            }\n//\n//            snapshotRepository(url: \"https://oss.sonatype.org/content/repositories/snapshots/\") {\n//                authentication(userName: ossrhUsername, password: ossrhPassword)\n//            }\n//\n//            pom.project {\n//                name 'SharedPreferences Annotations'\n//                packaging 'jar'\n//                // optionally artifactId can be defined here\n//                description 'Annotations to generate Source Code ' +\n//                        'used by the Annotation Processor in cn.framework.oksharedpref:processor'\n//                url 'https://github.com/sevenshal/oksharedpref-api'\n//\n//                scm {\n//                    connection 'scm:git:ssh://git@github.com/sevenshal/oksharedpref-api.git'\n//                    developerConnection 'scm:git:ssh://git@github.com/sevenshal/oksharedpref-api.git'\n//                    url 'https://github.com/sevenshal/oksharedpref-api'\n//                }\n//\n//                licenses {\n//                    license {\n//                        name 'MIT License'\n//                        url 'http://www.opensource.org/licenses/mit-license.php'\n//                    }\n//                }\n//\n//                developers {\n//                    developer {\n//                        id 'sevenshal'\n//                        name 'David Medenjak'\n//                        email 'davidmedenjak@gmail.com'\n//                        url 'https://github.com/sevenshal '\n//                        roles {\n//                            role 'owner'\n//                            role 'developer'\n//                        }\n//                        timezone '+1'\n//                    }\n//                }\n//            }\n        }\n    }\n}"
  },
  {
    "path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/DefaultValue.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Used to set the default value for this preference. THis value is supplied as String, because\n * the code is generated and the value simply inserted as is. Please be sure to support a valid\n * value.\n * <p>By setting {@link #createDefaultGetter} to <b>false</b> you\n * can suppress the additional getter of the form <em>get(Type defaultValue)</em>.</p>\n *\n * @author sevenshal\n * @version 1.0\n */\n@Retention(RetentionPolicy.SOURCE)\n@Target(ElementType.FIELD)\npublic @interface DefaultValue {\n    /**\n     * Supplies the default value to use for a preference in String format. e.g. \"3.0f\", \"hi\", ...\n     * @return the value to use as String.\n     */\n    String value();\n\n    /**\n     * Used to specify the creation of the default getter of the form <em>get(Type defaultValue)</em>.\n     * @return default true, to create the default getter nonetheless.\n     */\n    boolean createDefaultGetter() default true;\n}\n"
  },
  {
    "path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/PreferenceType.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations;\n\n/**\n * The usable types of the properties in the preferences. Used to set the return type\n * and parameters.\n * <p>\n * {@link #BOOLEAN}</p><p>\n * {@link #FLOAT}</p><p>\n * {@link #INTEGER}</p><p>\n * {@link #LONG}</p><p>\n * {@link #STRING}</p><p>\n * {@link #STRING_SET}</p>\n *\n * @author sevenshal\n * @version 1.0\n */\npublic enum PreferenceType {\n    /**\n     * Standard java boolean.\n     *\n     * @see Boolean\n     */\n    BOOLEAN(\"boolean\", \"Boolean\"),\n    /**\n     * Standard java floating point number.\n     *\n     * @see Float\n     */\n    FLOAT(\"float\", \"Float\"),\n    /**\n     * Standard java number.\n     *\n     * @see Integer\n     */\n    INTEGER(\"int\", \"Int\"),\n    /**\n     * Standard java long.\n     *\n     * @see Long\n     */\n    LONG(\"long\", \"Long\"),\n    /**\n     * Standard java String.\n     *\n     * @see String\n     */\n    STRING(\"String\", \"String\"),\n    /**\n     * A set of Strings.\n     *\n     * @see String\n     * @see java.util.Set\n     */\n    STRING_SET(\"Set<String>\", \"StringSet\");\n\n    private String returnType;\n    private String fullName;\n\n    PreferenceType(String returnType, String fullName) {\n        this.returnType = returnType;\n        this.fullName = fullName;\n    }\n\n    /**\n     * Method to supply the spelling for the type as a return type.\n     *\n     * @return the type as String usable for method declarations.\n     */\n    public String getReturnType() {\n        return returnType;\n    }\n\n    /**\n     * Method to supply the type as a String used for the getter methods. e.g. <em>getString()</em>\n     *\n     * @return the type as String, CamelCase.\n     */\n    public String getFullName() {\n        return fullName;\n    }\n}\n"
  },
  {
    "path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/SharedPreference.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>Annotation to generate a default wrapper class for the annotated interface.\n * Supply a String value\n * to change the name of the genereated class to <i>value</i>Prefs and <i>value</i>Editor.\n * </p>\n * <p>By not specifying a value <i>DefaultPrefs</i> and <i>DefaultEditor</i> will be generated.</p>\n * <p>\n * <p>Additionally you may change the class name suffixes by setting {@link #preferencesSuffix()}\n * or {@link #editorSuffix()}.</p>\n */\n\n@Retention(RetentionPolicy.SOURCE)\n@Target(ElementType.TYPE)\npublic @interface SharedPreference {\n    /**\n     * the prefix for the generated preferences and editor.\n     *\n     * @return the prefix, the name of the annotated interface by default.\n     */\n    String value() default \"\";\n\n    /**\n     * the suffix for the preferences.\n     *\n     * @return the suffix, \"Prefs\" by default.\n     */\n    String preferencesSuffix() default \"Prefs\";\n\n    /**\n     * preferences name which used by getSharedPreferences(preferenceName).\n     * @return the name, \"default_preferences\" by default.\n     */\n    String preferenceName() default \"default_preferences\";\n\n    /**\n     * Set the default type for all the contained properties in the interface if not specified.\n     * To use a different type for a single property\n     * annotate the properties with {@link Type}.\n     * @return the default type, PreferenceType.STRING by default.\n     */\n    PreferenceType defaultPreferenceType() default PreferenceType.STRING;\n\n    /**\n     * the suffix for the editor.\n     *\n     * @return the suffix, \"Editor\" by default.\n     */\n    String editorSuffix() default \"Editor\";\n\n    /**\n     * implement interface of SharedPreference if true\n     *\n     * @return true\n     */\n    boolean implSharedPreference() default true;\n\n    /**\n     * the sharedpreference can be used in multiprocess safely if true.\n     * @return\n     */\n    boolean multiProcess() default false;\n}\n"
  },
  {
    "path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/Type.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations;\n\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>The preferences type of this single property.\n * The getter and setter will be genereated with the supplied type.</p>\n * Supported types are of {@link PreferenceType}\n *\n * @author sevenshal\n * @version 1.0\n */\n@Retention(RetentionPolicy.SOURCE)\n@Target(ElementType.FIELD)\npublic @interface Type {\n    /**\n     * the type of the preference element.\n     *\n     * @return the type\n     */\n    PreferenceType value();\n\n    /**\n     * <b>if</b> the type is a boolean, you can set the getter prefix here.\n     *\n     * @return the prefix for the getter, \"is\" by default.\n     */\n    String booleanPrefix() default \"is\";\n}\n"
  },
  {
    "path": "api/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "api/build.gradle",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nbuildscript {\n    repositories {\n        mavenLocal()\n//        mavenCentral()\n    }\n}\napply plugin: 'com.android.library'\napply plugin: 'com.github.dcendents.android-maven'\n\napply plugin: 'maven'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion '26.0.2'\n    defaultConfig {\n        minSdkVersion 11\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\narchivesBaseName = \"api\"\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(':annotations')\n}\n\n//signing {\n//    sign configurations.archives\n//}\n\ndef ossrhUsername = System.properties['ossrhUsername']\ndef ossrhPassword = System.properties['ossrhPassword']\n\nuploadArchives {\n    repositories {\n        mavenDeployer {\n            repository(url: mavenLocal().getUrl())\n        }\n    }\n}"
  },
  {
    "path": "api/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"cn.framework.oksharedpref\">\n\n    <application>\n        <provider android:name=\"cn.framework.oksharedpref.OkSharedPrefContentProvider\"\n            android:authorities=\"${applicationId}.oksharedpref\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "api/src/main/java/cn/framework/oksharedpref/MPSPUtils.java",
    "content": "package cn.framework.oksharedpref;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.pm.ProviderInfo;\nimport android.os.Process;\nimport android.text.TextUtils;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.util.Locale;\n\n/**\n * Created by sevenshal on 2017/10/26.\n */\n\npublic class MPSPUtils {\n\n    private static Boolean isProviderProcess;\n\n    private static boolean isProviderProcess(Context ctx) {\n        if (isProviderProcess != null) {\n            return isProviderProcess;\n        }\n        String processCmdPath = String.format(Locale.getDefault(),\n                \"/proc/%d/cmdline\", Process.myPid());\n        BufferedReader inputStream = null;\n        try {\n            inputStream = new BufferedReader(new FileReader(\n                    processCmdPath));\n            String processName = inputStream.readLine().trim();\n            ProviderInfo providerInfo = ctx.getPackageManager().getProviderInfo(new ComponentName(ctx, OkSharedPrefContentProvider.class), 0);\n            isProviderProcess = TextUtils.equals(providerInfo.processName, processName);\n            return isProviderProcess;\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                if (inputStream != null) {\n                    inputStream.close();\n                }\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static SharedPreferences getSharedPref(Context ctx, String name) {\n        SharedPreferences preferences;\n        if (MPSPUtils.isProviderProcess(ctx)) {\n            preferences = ctx.getSharedPreferences(name, Context.MODE_PRIVATE);\n        } else {\n            preferences = OkSharedPrefContentProvider.getSharedPreferences(ctx, name, Context.MODE_PRIVATE);\n        }\n        return preferences;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/cn/framework/oksharedpref/OkSharedPrefContentProvider.java",
    "content": "package cn.framework.oksharedpref;\n\nimport android.content.ContentProvider;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.database.ContentObserver;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport java.lang.ref.WeakReference;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * 使用ContentProvider实现多进程SharedPreferences读写\n */\npublic class OkSharedPrefContentProvider extends ContentProvider {\n    private static final String TAG = \"MPSP\";\n\n    private static String AUTHORITY;\n    private static volatile Uri AUTHORITY_URI;\n    private static final String METHOD_MP = \"multi_process\";\n    private static final String KEY = \"key\";\n    private static final String KEY_TYPE = \"type\";\n    private static final String KEY_MODE = \"mode\";\n    private static final String KEY_VALUE = \"value\";\n    private static final String KEY_CLEAR = \"clear\";\n\n    private static final int GET_ALL = 1;\n    private static final int GET_STRING = 2;\n    private static final int GET_INT = 3;\n    private static final int GET_LONG = 4;\n    private static final int GET_FLOAT = 5;\n    private static final int GET_BOOLEAN = 6;\n    private static final int GET_STRING_SET = 7;\n    private static final int CONTAINS = 8;\n    private static final int APPLY = 9;\n    private static final int COMMIT = 10;\n\n    private HashMap<String, SharedPreferences.OnSharedPreferenceChangeListener> listenerHashMap;\n\n    private static Bundle handle(SharedPreferences sp, Bundle extras) {\n        String key = extras.getString(KEY);\n        int type = extras.getInt(KEY_TYPE);\n        Bundle bundle = new Bundle();\n        switch (type) {\n            case GET_ALL:\n                bundle.putSerializable(KEY_VALUE, new HashMap(sp.getAll()));\n                break;\n            case GET_STRING:\n                bundle.putString(KEY_VALUE, sp.getString(key, extras.getString(KEY_VALUE)));\n                break;\n            case GET_INT:\n                bundle.putInt(KEY_VALUE, sp.getInt(key, extras.getInt(KEY_VALUE)));\n                break;\n            case GET_LONG:\n                bundle.putLong(KEY_VALUE, sp.getLong(key, extras.getLong(KEY_VALUE)));\n                break;\n            case GET_FLOAT:\n                bundle.putFloat(KEY_VALUE, sp.getFloat(key, extras.getFloat(KEY_VALUE)));\n                break;\n            case GET_BOOLEAN:\n                bundle.putBoolean(KEY_VALUE, sp.getBoolean(key, extras.getBoolean(KEY_VALUE)));\n                break;\n            case GET_STRING_SET:\n                bundle.putSerializable(KEY_VALUE, wrapperSet(\n                        sp.getStringSet(key, (Set<String>) extras.getSerializable(KEY_VALUE))));\n                break;\n            case CONTAINS:\n                bundle.putBoolean(KEY_VALUE, sp.contains(key));\n                break;\n            case APPLY:\n            case COMMIT:\n                boolean clear = extras.getBoolean(KEY_CLEAR, false);\n                SharedPreferences.Editor editor = sp.edit();\n                if (clear) {\n                    editor.clear();\n                }\n                HashMap<String, ?> values = (HashMap) extras.getSerializable(KEY_VALUE);\n                for (Map.Entry entry : values.entrySet()) {\n                    String k = (String) entry.getKey();\n                    Object v = entry.getValue();\n                    if (v == null) {\n                        editor.remove(k);\n                    } else if (v instanceof String) {\n                        editor.putString(k, (String) v);\n                    } else if (v instanceof Set) {\n                        editor.putStringSet(k, (Set) v);\n                    } else if (v instanceof Integer) {\n                        editor.putInt(k, (Integer) v);\n                    } else if (v instanceof Long) {\n                        editor.putLong(k, (Long) v);\n                    } else if (v instanceof Float) {\n                        editor.putFloat(k, (Float) v);\n                    } else if (v instanceof Boolean) {\n                        editor.putBoolean(k, (Boolean) v);\n                    }\n                }\n                if (type == APPLY) {\n                    editor.apply();\n                    bundle.putBoolean(KEY_VALUE, true);\n                } else {\n                    bundle.putBoolean(KEY_VALUE, editor.commit());\n                }\n                break;\n            default:\n                break;\n        }\n        return bundle;\n    }\n\n    @Override\n    public Bundle call(String method, String name, Bundle extras) {\n        if (!method.equals(METHOD_MP)) {\n            return null;\n        }\n        int mode = extras.getInt(KEY_MODE);\n        SharedPreferences sp = getContext().getSharedPreferences(name, mode);\n        registListener(sp, name);\n        return handle(sp, extras);\n    }\n\n    void registListener(SharedPreferences pref, final String name) {\n        if (listenerHashMap == null || listenerHashMap.get(name) == null) {\n            synchronized (MPSPUtils.class) {\n                if (listenerHashMap == null) {\n                    listenerHashMap = new HashMap<>();\n                }\n                if (listenerHashMap.get(name) == null) {\n                    SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences\n                            .OnSharedPreferenceChangeListener() {\n                        @Override\n                        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {\n                            Uri uri = Uri.withAppendedPath(OkSharedPrefContentProvider.getAuthorityUri(getContext(), name), key);\n                            getContext().getContentResolver().notifyChange(uri, null);\n                        }\n                    };\n                    pref.registerOnSharedPreferenceChangeListener(listener);\n                    listenerHashMap.put(name, listener);\n                }\n            }\n        }\n    }\n\n    /**\n     * 如果设备处在“安全模式”下，只有系统自带的ContentProvider才能被正常解析使用；\n     */\n    private static boolean isSafeMode(Context context) {\n        boolean isSafeMode = false;\n        try {\n            isSafeMode = context.getPackageManager().isSafeMode();\n            // 解决崩溃：\n            // java.lang.RuntimeException: Package manager has died\n            // at android.app.ApplicationPackageManager.isSafeMode(ApplicationPackageManager.java:820)\n        } catch (RuntimeException e) {\n            e.printStackTrace();\n        }\n        return isSafeMode;\n    }\n\n    public static Uri getAuthorityUri(Context context, String name) {\n        if (AUTHORITY_URI == null) {\n            synchronized (OkSharedPrefContentProvider.class) {\n                if (AUTHORITY_URI == null) {\n                    if (AUTHORITY == null) {\n                        AUTHORITY = context.getPackageName() + \".oksharedpref\";\n                    }\n                    AUTHORITY_URI = Uri.parse(ContentResolver.SCHEME_CONTENT + \"://\" + AUTHORITY);\n                }\n            }\n        }\n        return Uri.withAppendedPath(AUTHORITY_URI, name);\n    }\n\n    /**\n     * 获取异常栈中最底层的 Throwable Cause；\n     *\n     * @param tr\n     * @return\n     */\n    private static Throwable getLastCause(Throwable tr) {\n        Throwable cause = tr.getCause();\n        Throwable causeLast = null;\n        while (cause != null) {\n            causeLast = cause;\n            cause = cause.getCause();\n        }\n        if (causeLast == null) {\n            causeLast = new Throwable();\n        }\n        return causeLast;\n    }\n\n    /**\n     * mode不使用{@link Context#MODE_MULTI_PROCESS}特可以支持多进程了；\n     *\n     * @param mode\n     * @see Context#MODE_PRIVATE\n     * @see Context#MODE_WORLD_READABLE\n     * @see Context#MODE_WORLD_WRITEABLE\n     */\n    public static SharedPreferences getSharedPreferences(Context context, String name, int mode) {\n        return isSafeMode(context) ? context.getSharedPreferences(name, mode) : new SharedPreferencesImpl(context, name, mode);\n    }\n\n    /**\n     * @deprecated 此默认构造函数只用于父类ContentProvider在初始化时使用；\n     */\n    @Deprecated\n    public OkSharedPrefContentProvider() {\n\n    }\n\n    private static final class SharedPreferencesImpl implements SharedPreferences {\n\n        private static Handler uiHandler = new Handler(Looper.getMainLooper());\n\n        private Context mContext;\n        private String mName;\n        private int mMode;\n        private WeakHashMap<OnSharedPreferenceChangeListener, ContentObserverImplHolder> mListeners;\n\n        private SharedPreferencesImpl(Context context, String name, int mode) {\n            mContext = context;\n            mName = name;\n            mMode = mode;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        public Map<String, ?> getAll() {\n            Map<String, ?> value = (Map<String, ?>) call(null, GET_ALL, new Bundle());\n            return value == null ? new HashMap<String, Object>() : value;\n        }\n\n        @Override\n        public String getString(String key, String defValue) {\n            Bundle arg = new Bundle();\n            arg.putString(KEY_VALUE, defValue);\n            return (String) call(key, GET_STRING, arg);\n        }\n\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public Set<String> getStringSet(String key, Set<String> defValues) {\n            Bundle arg = new Bundle();\n            arg.putSerializable(KEY_VALUE, wrapperSet(defValues));\n            return (Set<String>) call(key, GET_STRING_SET, arg);\n        }\n\n        @Override\n        public int getInt(String key, int defValue) {\n            Bundle arg = new Bundle();\n            arg.putInt(KEY_VALUE, defValue);\n            return (Integer) call(key, GET_INT, arg);\n        }\n\n        @Override\n        public long getLong(String key, long defValue) {\n            Bundle arg = new Bundle();\n            arg.putLong(KEY_VALUE, defValue);\n            return (Long) call(key, GET_LONG, arg);\n        }\n\n        @Override\n        public float getFloat(String key, float defValue) {\n            Bundle arg = new Bundle();\n            arg.putFloat(KEY_VALUE, defValue);\n            return (Float) call(key, GET_FLOAT, arg);\n        }\n\n        @Override\n        public boolean getBoolean(String key, boolean defValue) {\n            Bundle arg = new Bundle();\n            arg.putBoolean(KEY_VALUE, defValue);\n            return (Boolean) call(key, GET_BOOLEAN, arg);\n        }\n\n        @Override\n        public boolean contains(String key) {\n            return (Boolean) call(key, CONTAINS, new Bundle());\n        }\n\n        @Override\n        public Editor edit() {\n            return new EditorImpl();\n        }\n\n        @Override\n        public void registerOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) {\n            Uri uri = getAuthorityUri(mContext, mName);\n            ContentObserverImplHolder observer = new ContentObserverImplHolder(listener);\n            mContext.getContentResolver()\n                    .registerContentObserver(uri, true, observer.observer);\n            getListeners().put(listener, observer);\n        }\n\n        @Override\n        public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {\n            ContentObserverImplHolder holder = getListeners().remove(listener);\n            if (holder != null) {\n                holder.observer.destroy();\n            }\n        }\n\n        private Map<OnSharedPreferenceChangeListener, ContentObserverImplHolder> getListeners() {\n            if (mListeners == null) {\n                synchronized (this) {\n                    if (mListeners == null) {\n                        mListeners = new WeakHashMap<>();\n                    }\n                }\n            }\n            return mListeners;\n        }\n\n        private class ContentObserverImplHolder {\n            ContentObserverImpl observer;\n\n            ContentObserverImplHolder(OnSharedPreferenceChangeListener listener) {\n                observer = new ContentObserverImpl(listener);\n            }\n\n            @Override\n            protected void finalize() throws Throwable {\n                try {\n                    observer.destroy();\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n                super.finalize();\n            }\n        }\n\n        private class ContentObserverImpl extends ContentObserver {\n\n            private WeakReference<OnSharedPreferenceChangeListener> listenerRef;\n\n            private boolean destroy;\n\n            private ContentObserverImpl(OnSharedPreferenceChangeListener listener) {\n                super(uiHandler);\n                this.listenerRef = new WeakReference<OnSharedPreferenceChangeListener>(listener);\n            }\n\n            public void destroy() {\n                if (!destroy) {\n                    synchronized (this) {\n                        if (!destroy) {\n                            mContext.getContentResolver()\n                                    .unregisterContentObserver(this);\n                            destroy = true;\n                        }\n                    }\n                }\n            }\n\n            @Override\n            public void onChange(boolean selfChange, Uri uri) {\n                OnSharedPreferenceChangeListener listener = listenerRef.get();\n                if (listener != null) {\n                    listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, uri.getLastPathSegment());\n                } else {\n                    destroy();\n                }\n            }\n        }\n\n        private Object call(String key, int type, Bundle arg) {\n            Uri uri = getAuthorityUri(mContext, mName);\n            arg.putInt(KEY_MODE, mMode);\n            arg.putString(KEY, key);\n            arg.putInt(KEY_TYPE, type);\n            try {\n                Bundle ret = mContext.getContentResolver().call(uri, METHOD_MP, mName, arg);\n                return ret.get(KEY_VALUE);\n            } catch (Throwable e) {\n                e.printStackTrace();\n                return handle(mContext.getSharedPreferences(mName, mMode), arg).get(KEY_VALUE);\n            }\n        }\n\n        public final class EditorImpl implements Editor {\n            private final HashMap<String, Object> mModified = new HashMap();\n            private boolean mClear = false;\n\n            @Override\n            public Editor putString(String key, String value) {\n                synchronized (this) {\n                    mModified.put(key, value);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor putStringSet(String key, Set<String> values) {\n                synchronized (this) {\n                    mModified.put(key, values);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor putInt(String key, int value) {\n                synchronized (this) {\n                    mModified.put(key, value);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor putLong(String key, long value) {\n                synchronized (this) {\n                    mModified.put(key, value);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor putFloat(String key, float value) {\n                synchronized (this) {\n                    mModified.put(key, value);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor putBoolean(String key, boolean value) {\n                synchronized (this) {\n                    mModified.put(key, value);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor remove(String key) {\n                synchronized (this) {\n                    mModified.put(key, null);\n                    return this;\n                }\n            }\n\n            @Override\n            public Editor clear() {\n                synchronized (this) {\n                    mModified.clear();\n                    mClear = true;\n                    return this;\n                }\n            }\n\n            @Override\n            public void apply() {\n                setValue(APPLY);\n            }\n\n            @Override\n            public boolean commit() {\n                return setValue(COMMIT);\n            }\n\n            private boolean setValue(int type) {\n                Bundle extras = new Bundle();\n                extras.putSerializable(KEY_VALUE, mModified);\n                extras.putBoolean(KEY_CLEAR, mClear);\n                return (Boolean) call(null, type, extras);\n            }\n        }\n\n    }\n\n    private static HashSet<String> wrapperSet(Set<String> set) {\n        return set == null ? null : (set instanceof HashMap ? (HashSet<String>) set : new HashSet<String>(set));\n    }\n\n    private static String makeAction(String name) {\n        return String.format(\"%1$s_%2$s\", OkSharedPrefContentProvider.class.getName(), name);\n    }\n\n    @Override\n    public boolean onCreate() {\n        return true;\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        throw new UnsupportedOperationException(\" No external query\");\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        throw new UnsupportedOperationException(\" No external update\");\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        throw new UnsupportedOperationException(\"No external call\");\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        throw new UnsupportedOperationException(\"No external insert\");\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        throw new UnsupportedOperationException(\"No external delete\");\n    }\n\n}"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion '26.0.2'\n    defaultConfig {\n        applicationId \"cn.framework.sharedpref.app\"\n        minSdkVersion 11\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n    compile 'com.android.support.constraint:constraint-layout:1.0.2'\n    testCompile 'junit:junit:4.12'\n\n    compile 'com.github.sevenshal.oksharedprefs:api:1.0.1'\n    annotationProcessor 'com.github.sevenshal.oksharedprefs:processor:1.0.1'\n\n//    compile project(':api')\n//    annotationProcessor project(':processor')\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 /Users/sevenshal/Library/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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/cn/framework/ExampleInstrumentedTest.java",
    "content": "package cn.framework;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"cn.framework\", appContext.getPackageName());\n    }\n}\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=\"cn.framework\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".oksharedpref.app.MainActivity\"\n            android:label=\"@string/app_name\"\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        <activity\n            android:name=\".oksharedpref.app.SeActivity\"\n            android:label=\"@string/app_name\"\n            android:process=\":new\"\n            android:theme=\"@style/AppTheme.NoActionBar\">\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/cn/framework/oksharedpref/app/IMsg.java",
    "content": "package cn.framework.oksharedpref.app;\n\n\nimport cn.framework.oksharedpref.annotations.DefaultValue;\nimport cn.framework.oksharedpref.annotations.PreferenceType;\nimport cn.framework.oksharedpref.annotations.SharedPreference;\nimport cn.framework.oksharedpref.annotations.Type;\n\n/**\n * Created by sevenshal on 2016/11/28.\n */\n\n@SharedPreference(value = \"Msg\", implSharedPreference = false, preferenceName = \"msg\", multiProcess = false)\npublic interface IMsg {\n\n    @DefaultValue(value = \"null\", createDefaultGetter = false)\n    String USERID = \"userId\";\n\n    @Type(PreferenceType.STRING_SET)\n    @DefaultValue(value = \"null\", createDefaultGetter = false)\n    String TOKEN = \"token\";\n\n    @Type(PreferenceType.LONG)\n    @DefaultValue(value = \"0\", createDefaultGetter = false)\n    String DEVICE_ID = \"deviceId\";\n\n    @Type(PreferenceType.BOOLEAN)\n    @DefaultValue(value = \"false\", createDefaultGetter = false)\n    String LOGIN = \"hasAuth\";\n\n    String NICK_NAME = \"nickName\";\n\n}\n"
  },
  {
    "path": "app/src/main/java/cn/framework/oksharedpref/app/MainActivity.java",
    "content": "package cn.framework.oksharedpref.app;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport cn.framework.R;\n\npublic class MainActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {\n\n    MsgPrefs msgPrefs;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                startActivity(new Intent(MainActivity.this, SeActivity.class));\n            }\n        });\n\n        msgPrefs = MsgPrefs.defaultInstance(this);\n        Log.i(\"MPM\", \"deviceId:\" + msgPrefs.getDeviceId()\n                + \";userId:\" + msgPrefs.getUserid()\n                + \";isLogin:\" + msgPrefs.isLogin() + \";token:\" + msgPrefs.getToken());\n\n        msgPrefs.prefs().registerOnSharedPreferenceChangeListener(this);\n\n        Set set = new HashSet<String>();\n        set.add(\"a\");\n        set.add(\"b\");\n        msgPrefs.edit().setDeviceId(111).setLogin(true).setUserid(\"userid\").setToken(set).apply();\n    }\n\n    @Override\n    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {\n        Log.i(\"MP\", \"main_onSharedPreferenceChanged:\" + key);\n        Log.i(\"MPM\", \"deviceId:\" + msgPrefs.getDeviceId()\n                + \";userId:\" + msgPrefs.getUserid()\n                + \";isLogin:\" + msgPrefs.isLogin() + \";token:\" + msgPrefs.getToken());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/framework/oksharedpref/app/SeActivity.java",
    "content": "package cn.framework.oksharedpref.app;\n\nimport android.app.Activity;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Created by sevenshal on 2017/10/23.\n */\n\npublic class SeActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {\n\n    MsgPrefs msgPrefs;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        msgPrefs = MsgPrefs.defaultInstance(this);\n        Log.i(\"MPM\", \"deviceId:\" + msgPrefs.getDeviceId()\n                + \";userId:\" + msgPrefs.getUserid()\n                + \";isLogin:\" + msgPrefs.isLogin() + \";token:\" + msgPrefs.getToken());\n\n        Set set = new HashSet<String>();\n        set.add(\"a2\");\n        set.add(\"b2\");\n\n        msgPrefs.prefs().registerOnSharedPreferenceChangeListener(this);\n\n        msgPrefs.edit().setToken(set).setUserid(\"userid2\").setLogin(false).setDeviceId(222).apply();\n    }\n\n    @Override\n    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {\n        Log.i(\"MP\", \"onSharedPreferenceChanged:\" + key);\n        Log.i(\"MPM\", \"deviceId:\" + msgPrefs.getDeviceId()\n                + \";userId:\" + msgPrefs.getUserid()\n                + \";isLogin:\" + msgPrefs.isLogin() + \";token:\" + msgPrefs.getToken());\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        msgPrefs.prefs().unregisterOnSharedPreferenceChangeListener(this);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.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\n    <Button\n        android:id=\"@+id/btn\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:text=\"startNewProcessActivity\"/>\n\n</LinearLayout>\n"
  },
  {
    "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    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Hello World!\" />\n\n</LinearLayout>\n"
  },
  {
    "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    <dimen name=\"fab_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">MultiProcessSharepref</string>\n    <string name=\"action_settings\">Settings</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"android:Theme\">\n        <!-- Customize your theme here. -->\n    </style>\n\n    <style name=\"AppTheme.NoActionBar\" parent=\"android:Theme.Holo.NoActionBar\">\n    </style>\n\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"android:Theme\" />\n\n    <style name=\"AppTheme.PopupOverlay\" parent=\"android:Theme.Holo.Light\" />\n\n</resources>\n"
  },
  {
    "path": "app/src/test/java/cn/framework/ExampleUnitTest.java",
    "content": "package cn.framework;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\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        mavenLocal()\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.0.1'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'\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        mavenLocal()\n        google()\n        jcenter()\n        maven { url 'https://jitpack.io' }\n    }\n\n    group = 'cn.framework.oksharedpref'\n    version = '1.0.0'\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Nov 01 14:56:37 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\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.\norg.gradle.jvmargs=-Xmx1536m\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"
  },
  {
    "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": "processor/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "processor/build.gradle",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nbuildscript {\n    repositories {\n        mavenLocal()\n//        mavenCentral()\n    }\n}\n\napply plugin: 'java'\napply plugin: 'maven'\n//apply plugin: 'signing'\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(':annotations')\n    compile 'com.squareup:javawriter:2.5.1'\n    compile 'com.google.android:android:4.1.1.4'\n}\n\narchivesBaseName = \"processor\"\n\ntask javadocJar(type: Jar) {\n    classifier = 'javadoc'\n    from javadoc\n}\n\ntask sourcesJar(type: Jar) {\n    classifier = 'sources'\n    from sourceSets.main.allSource\n}\n\nartifacts {\n    archives javadocJar, sourcesJar\n}\n\n//signing {\n//    sign configurations.archives\n//}\n\ndef ossrhUsername = System.properties['ossrhUsername']\ndef ossrhPassword = System.properties['ossrhPassword']\n\nuploadArchives {\n    repositories {\n        mavenDeployer {\n            repository(url: mavenLocal().getUrl())\n        }\n    }\n}"
  },
  {
    "path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Modifier.java",
    "content": "package cn.framework.oksharedpref.annotations.processor;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\n/**\n * Created by David on 25.01.2015.\n */\nclass Modifier {\n    final static Set<javax.lang.model.element.Modifier> PUBLIC_STATIC = new LinkedHashSet<>();\n    final static Set<javax.lang.model.element.Modifier> PUBLIC = new LinkedHashSet<>();\n    final static Set<javax.lang.model.element.Modifier> PRIVATE = new LinkedHashSet<>();\n    final static Set<javax.lang.model.element.Modifier> PRIVATE_STATIC = new LinkedHashSet<>();\n    final static Set<javax.lang.model.element.Modifier> PRIVATE_FINAL = new LinkedHashSet<>();\n    final static Set<javax.lang.model.element.Modifier> PUBLIC_FINAL_STATIC = new LinkedHashSet<>();\n\n    static {\n        PUBLIC_STATIC.add(javax.lang.model.element.Modifier.PUBLIC);\n        PUBLIC_STATIC.add(javax.lang.model.element.Modifier.STATIC);\n        PUBLIC.add(javax.lang.model.element.Modifier.PUBLIC);\n        PRIVATE_FINAL.add(javax.lang.model.element.Modifier.PRIVATE);\n        PRIVATE_FINAL.add(javax.lang.model.element.Modifier.FINAL);\n        PUBLIC_FINAL_STATIC.add(javax.lang.model.element.Modifier.PUBLIC);\n        PUBLIC_FINAL_STATIC.add(javax.lang.model.element.Modifier.FINAL);\n        PUBLIC_FINAL_STATIC.add(javax.lang.model.element.Modifier.STATIC);\n        PRIVATE.add(javax.lang.model.element.Modifier.PRIVATE);\n        PRIVATE_STATIC.add(javax.lang.model.element.Modifier.PRIVATE);\n        PRIVATE_STATIC.add(javax.lang.model.element.Modifier.STATIC);\n    }\n}\n"
  },
  {
    "path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Preference.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations.processor;\n\nimport com.squareup.javawriter.JavaWriter;\n\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.VariableElement;\n\nimport cn.framework.oksharedpref.annotations.DefaultValue;\nimport cn.framework.oksharedpref.annotations.PreferenceType;\nimport cn.framework.oksharedpref.annotations.Type;\n\n/**\n * @author sevenshal\n * @version 1.0\n */\npublic class Preference {\n    private static final Set<Modifier> setPublic;\n\n    static {\n        setPublic = new HashSet<>();\n        setPublic.add(Modifier.PUBLIC);\n    }\n\n    private static final String PARAM_DEFAULT_VALUE = \"defaultValue\";\n    private static final String VALUE = \"value\";\n\n    private final VariableElement mElement;\n    private final PreferenceType mType;\n    private final String mPreferenceName;\n    private final String mpreferenceFieldName;\n    private final String mPreferenceId;\n    private final String mBooleanPrefix;\n    private final boolean hasDefaultValue;\n    private final boolean createDefaultGetter;\n    private final String mDefaultValue;\n\n    public static String camelCaseName(String name) {\n        String[] split = name.toLowerCase().split(\"_\");\n        String ret = split[0];\n        for (int i = 1; i < split.length; i++) {\n            ret += Character.toUpperCase(split[i].charAt(0)) + split[i].substring(1);\n        }\n        return ret;\n    }\n\n    public Preference(String preferenceName, String preferenceId, VariableElement element, PreferenceType defaultType) {\n        String camelCaseName = camelCaseName(preferenceName);\n        mPreferenceName = Character.toUpperCase(camelCaseName.charAt(0)) + camelCaseName.substring(1);\n        mpreferenceFieldName = preferenceName;\n        mPreferenceId = preferenceId;\n        mElement = element;\n        Type type = element.getAnnotation(Type.class);\n        if (type == null) {\n            mType = defaultType != null ? defaultType : PreferenceType.STRING;\n            mBooleanPrefix = \"is\";\n        } else {\n            mType = type.value();\n            mBooleanPrefix = type.booleanPrefix();\n        }\n\n        DefaultValue defValue = element.getAnnotation(DefaultValue.class);\n        if (defValue != null) {\n            hasDefaultValue = true;\n            mDefaultValue = defValue.value();\n            createDefaultGetter = defValue.createDefaultGetter();\n        } else {\n            hasDefaultValue = false;\n            createDefaultGetter = true;\n            mDefaultValue = null;\n        }\n    }\n\n    public VariableElement getElement() {\n        return mElement;\n    }\n\n    public void writeGetter(JavaWriter writer) throws IOException {\n        final String prefix = mType == PreferenceType.BOOLEAN ? mBooleanPrefix : \"get\";\n\n        // Create getter() for default value\n        if (hasDefaultValue) {\n            writer.emitEmptyLine().emitJavadoc(\"gets '%s' from the preferences, <b>%s</b> by default if not yet set.\", mPreferenceId, mDefaultValue)\n                    .beginMethod(mType.getReturnType(), prefix + mPreferenceName, setPublic)\n                    .emitStatement(\"return mPreferences.get%1$s(%2$s, %3$s)\", mType.getFullName(), mpreferenceFieldName, mDefaultValue).endMethod();\n        }\n        if (!createDefaultGetter)\n            return;\n        writer.emitEmptyLine().emitJavadoc(\"gets '%s' from the preferences.\\n@param %s the default value to use\", mPreferenceId, PARAM_DEFAULT_VALUE)\n                .beginMethod(mType.getReturnType(), prefix + mPreferenceName, setPublic, mType.getReturnType(), PARAM_DEFAULT_VALUE)\n                .emitStatement(\"return mPreferences.get%1$s(%2$s, %3$s)\", mType.getFullName(), mpreferenceFieldName, PARAM_DEFAULT_VALUE).endMethod();\n    }\n\n    public void writeSetter(JavaWriter writer) throws IOException {\n        writer.emitEmptyLine().emitJavadoc(\"sets '%1$s' in the preferences.\\n@param %2$s the new value for '%1$s'\", mPreferenceId, VALUE)\n                .beginMethod(\"void\", \"set\" + mPreferenceName, setPublic, mType.getReturnType(), VALUE)\n                .emitStatement(\"mPreferences.edit().put%1$s(%2$s, %3$s).apply()\", mType.getFullName(), mpreferenceFieldName, VALUE)\n                .endMethod();\n    }\n\n    public void writeChainSetter(JavaWriter writer, String editorType, String editor) throws IOException {\n        writer.emitEmptyLine().emitJavadoc(\"sets '%1$s' in the preferences.\\n@param %2$s the new value for '%1$s'\", mPreferenceId, VALUE)\n                .beginMethod(editorType, \"set\" + mPreferenceName, setPublic, mType.getReturnType(), VALUE)\n                .emitStatement(\"%1$s.put%2$s(%3$s, %4$s)\", editor, mType.getFullName(), mpreferenceFieldName, VALUE)\n                .emitStatement(\"return this\")\n                .endMethod();\n    }\n}\n"
  },
  {
    "path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/PreferenceHolder.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations.processor;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport com.squareup.javawriter.JavaWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport javax.annotation.processing.Filer;\nimport javax.annotation.processing.Messager;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.PackageElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.tools.Diagnostic;\nimport javax.tools.JavaFileObject;\n\nimport cn.framework.oksharedpref.annotations.PreferenceType;\nimport cn.framework.oksharedpref.annotations.SharedPreference;\n\n/**\n * @author sevenshal\n * @version 1.0\n */\npublic class PreferenceHolder {\n    private final static String PAR_CONTEXT = \"ctx\";\n    private final static String PAR_NAME = \"name\";\n    private final static String PAR_EDITOR = \"editor\";\n\n    private final static String PREFERENCES = \"mPreferences\";\n    private static final String EDITOR = \"mEditor\";\n\n    private final static String DEFAULT_INSTANCE = \"instance\";\n\n    private static final String DEFAULT_PREFERENCES_NAME = \"default_preferences\";\n\n    private final TypeElement mElement;\n    private final JavaWriter mWriter;\n\n    private final String preferencesName;\n    private final String className;\n    private final String editorName;\n    private final boolean implSharedPreference;\n    private final boolean multiProcess;\n\n    private final SortedMap<String, Preference> preferences = new TreeMap<>();\n\n\n    public PreferenceHolder(TypeElement element, Filer filer, Messager messager) throws IOException {\n        this.mElement = element;\n\n        // Set the name of the file / class and nested editor\n        SharedPreference sharedPreference = mElement.getAnnotation(SharedPreference.class);\n        final String name = (sharedPreference.value().isEmpty()) ? mElement.getSimpleName().toString()\n                : sharedPreference.value();\n        className = name + sharedPreference.preferencesSuffix();\n        editorName = name + sharedPreference.editorSuffix();\n        implSharedPreference = sharedPreference.implSharedPreference();\n        multiProcess = sharedPreference.multiProcess();\n        JavaFileObject jfo = filer.createSourceFile(getPackageName() + \".\" + className);\n        this.mWriter = new JavaWriter(jfo.openWriter());\n\n        // set the name of the sharedPreferences created with the context\n//        DefaultPreferenceName defName = element.getAnnotation(DefaultPreferenceName.class);\n        preferencesName = sharedPreference.preferenceName();\n\n        // default type if not specified\n        final PreferenceType defaultPreferenceType = sharedPreference.defaultPreferenceType();\n\n        Set<String> preferenceIds = new LinkedHashSet<>();\n        for (Element e : element.getEnclosedElements()) {\n            if (!e.getKind().isField()) {\n                messager.printMessage(Diagnostic.Kind.WARNING, e.getSimpleName() + \" is not a field\", e);\n                continue;\n            }\n            VariableElement var = (VariableElement) e;\n            if (!var.asType().toString().equals(\"java.lang.String\")) {\n                messager.printMessage(Diagnostic.Kind.WARNING, var.asType().toString() + \" is not of type String\", e);\n                continue;\n            }\n            if (var.getConstantValue() == null) {\n                messager.printMessage(Diagnostic.Kind.ERROR, var.getSimpleName() + \" is not final or no value is set\", e);\n                continue;\n            }\n\n            final String preferenceName = var.getSimpleName().toString();//Preference.camelCaseName(var.getSimpleName().toString());\n            Preference old = preferences.get(preferenceName);\n            if (old != null) {\n                messager.printMessage(Diagnostic.Kind.WARNING, preferenceName + \" used here is ignored\", var);\n                messager.printMessage(Diagnostic.Kind.WARNING, \"because it was already defined here\", old.getElement());\n                continue;\n            }\n            final String id = var.getConstantValue().toString();\n            if (!preferenceIds.add(id))\n                messager.printMessage(Diagnostic.Kind.WARNING, \"preference id \" + id + \" is already in use\");\n            preferences.put(preferenceName, new Preference(preferenceName, id, var, defaultPreferenceType));\n        }\n    }\n\n    public void write() throws IOException {\n        mWriter.setIndent(\"    \");\n        mWriter.emitPackage(getPackageName())\n                .emitSingleLineComment(\"generated code, do not modify\")\n                .emitSingleLineComment(\"for more information see https://github.com/sevenshal/oksharedpref-api\")\n                .emitEmptyLine()\n                .emitImports(Context.class, SharedPreferences.class)\n                .emitImports(\"android.content.SharedPreferences.Editor\",\n                        \"android.content.SharedPreferences.OnSharedPreferenceChangeListener\",\n                        \"cn.framework.oksharedpref.MPSPUtils\")\n                .emitEmptyLine()\n                .emitImports(Set.class)\n                .emitEmptyLine();\n        if (implSharedPreference) {\n            mWriter.beginType(className, \"class\", Modifier.PUBLIC,\n                    null, mElement.getSimpleName().toString(), \"SharedPreferences\");\n        } else {\n            mWriter.beginType(className, \"class\", Modifier.PUBLIC,\n                    null, mElement.getSimpleName().toString());\n        }\n        mWriter.emitEmptyLine();\n\n        mWriter.emitField(className, DEFAULT_INSTANCE, Modifier.PRIVATE_STATIC, null);\n\n        mWriter.emitField(\"String\", \"PREFERENCES_NAME\", Modifier.PUBLIC_FINAL_STATIC, \"\\\"\" + preferencesName + \"\\\"\")\n                .emitEmptyLine();\n\n        mWriter.emitField(\"SharedPreferences\", PREFERENCES, Modifier.PRIVATE_FINAL)\n                .emitEmptyLine();\n\n        mWriter.emitJavadoc(\"single instance using '%1$s' for preferences name.\\n@param %2$s the context to use\"\n                , preferencesName, PAR_CONTEXT)\n                .beginMethod(className, \"defaultInstance\", Modifier.PUBLIC_STATIC, \"Context\", PAR_CONTEXT)\n                .beginControlFlow(\"if (%1$s == null)\", DEFAULT_INSTANCE)\n                .beginControlFlow(\"synchronized (%1$s.class)\", className)\n                .beginControlFlow(\"if (%1$s == null)\", DEFAULT_INSTANCE)\n                .emitStatement(\"%1$s = new %2$s(%3$s.getApplicationContext())\", DEFAULT_INSTANCE, className, PAR_CONTEXT)\n                .endControlFlow()\n                .endControlFlow()\n                .endControlFlow()\n                .emitStatement(\"return instance\")\n                .endMethod()\n                .emitEmptyLine();\n\n        // default constructor with context using default preferences name\n        mWriter.emitJavadoc(\"constructor using '%1$s' for the preferences name.\\n@param %2$s the context to use\",\n                preferencesName, PAR_CONTEXT)\n                .beginConstructor(Modifier.PUBLIC, \"Context\", PAR_CONTEXT)\n                .emitStatement(\"this(%1$s, %2$s)\",\n                        PAR_CONTEXT, \"PREFERENCES_NAME\")\n                .endConstructor()\n                .emitEmptyLine();\n\n        // constructor with name for preferences\n        mWriter.emitJavadoc(\"constructor using <i>%2$s</i> for the preferences name.<br/>\\n<i>It is strongly advised against using it, unless you know what you're doing.</i>\\n\" +\n                        \"@param %3$s the context to use\\n@param %2$s the name for the preferences\",\n                preferencesName, PAR_NAME, PAR_CONTEXT)\n                .beginConstructor(Modifier.PUBLIC, \"Context\", PAR_CONTEXT, \"String\", PAR_NAME)\n                .emitStatement(multiProcess\n                                ? \"this.%1s = MPSPUtils.getSharedPref(%2s, %3s)\"\n                                : \"this.%1s = %2s.getSharedPreferences(%3s, Context.MODE_PRIVATE)\",\n                        PREFERENCES, PAR_CONTEXT, PAR_NAME)\n                .endConstructor();\n\n        // constructor with preferences\n//        mWriter.emitJavadoc(\"constructor using the supplied SharedPreferences\\n@param %1$s the SharedPreferences to use\\n\", \"preferences\")\n//                .beginConstructor(Modifier.PUBLIC, \"SharedPreferences\", \"preferences\")\n//                .emitStatement(\"this.%1s = preferences\",\n//                        PREFERENCES, \"preferences\")\n//                .endConstructor();\n\n        // implement SharedPreferences by just wrapping the shared preferences\n        if (implSharedPreference) {\n            wrapSharedPreferencesInterface(Modifier.PUBLIC, editorName, PREFERENCES, SharedPreferences.class.getMethods());\n        } else {\n            writeCommonMethod(Modifier.PUBLIC, editorName, EDITOR, SharedPreferences.Editor.class.getMethods());\n        }\n\n        // creating accessors for the fields annotated\n        for (Map.Entry<String, Preference> entry : preferences.entrySet()) {\n            entry.getValue().writeGetter(mWriter);\n            entry.getValue().writeSetter(mWriter);\n        }\n\n        // creating nested inner class for the editor\n        if (implSharedPreference) {\n            mWriter.emitEmptyLine().beginType(editorName, \"class\", Modifier.PUBLIC_STATIC, null, SharedPreferences.Editor.class.getCanonicalName());\n        } else {\n            mWriter.emitEmptyLine().beginType(editorName, \"class\", Modifier.PUBLIC_STATIC, null);\n        }\n        mWriter.emitEmptyLine()\n                .emitField(SharedPreferences.Editor.class.getCanonicalName(), EDITOR, Modifier.PRIVATE_FINAL)\n                .emitEmptyLine();\n        mWriter.beginConstructor(Modifier.PUBLIC,\n                SharedPreferences.Editor.class.getCanonicalName(), PAR_EDITOR)\n                .emitStatement(\"this.%1$s = %2$s\", EDITOR, PAR_EDITOR)\n                .endConstructor();\n        if (implSharedPreference) {\n            wrapEditorInterface(Modifier.PUBLIC, editorName, EDITOR, SharedPreferences.Editor.class.getMethods());\n        } else {\n            wrapEditorApplyMethod(Modifier.PUBLIC, editorName, EDITOR, SharedPreferences.Editor.class.getMethods());\n        }\n        // creating accessors for the fields annotated\n        for (Map.Entry<String, Preference> entry : preferences.entrySet()) {\n            entry.getValue().writeChainSetter(mWriter, editorName, EDITOR);\n        }\n        mWriter.endType();\n\n        mWriter.endType();\n        mWriter.close();\n    }\n\n    private void wrapSharedPreferencesInterface(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {\n        for (Method method : methods) {\n            mWriter.emitEmptyLine().emitAnnotation(Override.class);\n            boolean isCustomWrapperNeeded = method.getReturnType().equals(SharedPreferences.Editor.class);\n            final String params = beginMethod(modifiersPublic, editor, method, isCustomWrapperNeeded);\n\n            if (method.getReturnType().equals(void.class))\n                mWriter.emitStatement(\"%1$s.%2$s(%3$s)\", wrappedElement, method.getName(), params);\n            else {\n                if (isCustomWrapperNeeded)\n                    mWriter.emitStatement(\"return new %1$s(%2$s.%3$s(%4$s))\", editor, wrappedElement, method.getName(), params);\n                else\n                    mWriter.emitStatement(\"return %1$s.%2$s(%3$s)\", wrappedElement, method.getName(), params);\n            }\n            mWriter.endMethod();\n        }\n    }\n\n    private void writeCommonMethod(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {\n//        final String params = beginMethod(modifiersPublic, editor, method, isCustomWrapperNeeded);\n        mWriter.emitEmptyLine().beginMethod(editor, \"edit\", modifiersPublic)\n                .emitStatement(\"return new %1$s(mPreferences.edit())\", editor).endMethod();\n        mWriter.emitEmptyLine().beginMethod(\"SharedPreferences\", \"prefs\", modifiersPublic)\n                .emitStatement(\"return this.%1$s\", PREFERENCES).endMethod();\n\n    }\n\n    private void wrapEditorInterface(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {\n        for (Method method : methods) {\n            mWriter.emitEmptyLine().emitAnnotation(Override.class);\n            boolean isCustomWrapperNeeded = method.getReturnType().equals(SharedPreferences.Editor.class);\n            final String params = beginMethod(modifiersPublic, editor, method, isCustomWrapperNeeded);\n\n            if (method.getReturnType().equals(boolean.class))\n                mWriter.emitStatement(\"return %1$s.%2$s(%3$s)\", wrappedElement, method.getName(), params);\n            else {\n                mWriter.emitStatement(\"%1$s.%2$s(%3$s)\", wrappedElement, method.getName(), params);\n                if (!method.getReturnType().equals(void.class))\n                    mWriter.emitStatement(\"return this\");\n            }\n            mWriter.endMethod();\n        }\n    }\n\n    private void wrapEditorApplyMethod(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {\n        mWriter.emitEmptyLine().beginMethod(\"void\", \"apply\", modifiersPublic)\n                .emitStatement(\"%1$s.apply()\", wrappedElement);\n        mWriter.endMethod();\n    }\n\n    private String beginMethod(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, Method method, boolean isCustomWrapperNeeded) throws IOException {\n        String params = \"\";\n        final String retType = isCustomWrapperNeeded ?\n                editor : method.getGenericReturnType().getTypeName().replace('$', '.');\n        if (method.getParameterCount() > 0) {\n            String[] parameters = new String[method.getParameterCount() * 2];\n            for (int i = 0; i < method.getParameterCount(); i++) {\n                parameters[2 * i] = method.getGenericParameterTypes()[i].getTypeName().replace('$', '.');\n                parameters[2 * i + 1] = method.getParameters()[i].getName();\n                if (i > 0)\n                    params += \", \";\n                params += parameters[2 * i + 1];\n            }\n            mWriter.beginMethod(retType, method.getName(), modifiersPublic, parameters);\n        } else {\n            mWriter.beginMethod(retType, method.getName(), modifiersPublic);\n        }\n        return params;\n    }\n\n\n    public String getPackageName() {\n        Element enclosingElement = mElement.getEnclosingElement();\n        if (enclosingElement != null && enclosingElement instanceof PackageElement) {\n            return ((PackageElement) enclosingElement).getQualifiedName().toString();\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/SharedPreferencesAnnotationProcessor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage cn.framework.oksharedpref.annotations.processor;\n\n\nimport java.io.IOException;\nimport java.util.Set;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.tools.Diagnostic;\n\nimport cn.framework.oksharedpref.annotations.SharedPreference;\n\n\n@SupportedAnnotationTypes(\"cn.framework.oksharedpref.annotations.SharedPreference\")\n@SupportedSourceVersion(SourceVersion.RELEASE_7)\npublic class SharedPreferencesAnnotationProcessor extends AbstractProcessor {\n\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations,\n                           RoundEnvironment roundEnv) {\n        for (Element e : roundEnv.getElementsAnnotatedWith(SharedPreference.class)) {\n            if (e.getKind().isField()) {\n                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, \"Just interfaces annotated by @SharedPreference are supported.\", e);\n                continue;\n            }\n            if (e.getKind().isClass()) {\n                processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, \"Just interfaces annotated by @SharedPreference are supported.\", e);\n            }\n            PreferenceHolder prefHolder;\n            try {\n                prefHolder = new PreferenceHolder((TypeElement) e, processingEnv.getFiler(), processingEnv.getMessager());\n                prefHolder.write();\n            } catch (IOException ex) {\n                ex.printStackTrace();\n                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ex.getMessage(), e);\n            }\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor",
    "content": "cn.framework.oksharedpref.annotations.processor.SharedPreferencesAnnotationProcessor"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':api', ':annotations', ':processor'\n"
  }
]