[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches/build_file_checksums.ser\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <Objective-C-extensions>\n      <file>\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Import\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Macro\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Typedef\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Enum\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Constant\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Global\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Struct\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"FunctionPredecl\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Function\" />\n      </file>\n      <class>\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Property\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Synthesize\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InitMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"StaticMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InstanceMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"DeallocMethod\" />\n      </class>\n      <extensions>\n        <pair source=\"cpp\" header=\"h\" fileNamingConvention=\"NONE\" />\n        <pair source=\"c\" header=\"h\" fileNamingConvention=\"NONE\" />\n      </extensions>\n    </Objective-C-extensions>\n  </code_scheme>\n</component>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n            <option value=\"$PROJECT_DIR$/doubleclicklibrary\" />\n          </set>\n        </option>\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"7\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"javax.annotation.CheckForNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"4\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n          <item index=\"5\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.Nullable\" />\n          <item index=\"6\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.RecentlyNullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"6\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n          <item index=\"4\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.NonNull\" />\n          <item index=\"5\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.RecentlyNonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" project-jdk-name=\"1.8 (3)\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "# DoubleClick\n\n简书: \n[DoubleClick---3.0版本](https://www.jianshu.com/p/daac21821c43)\n\n[DoubleClick---2.0版本](https://www.jianshu.com/p/df0ef3866cc1)\n\n[DoubleClick---1.0版本](https://www.jianshu.com/p/7f3e5c8b8643)\n\n**V3.0 的使用方法:** \n\n**1.导入:**\n```\n//项目根目录下,build.gradle\nbuildscript {\n    ...\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.2.0'\n        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8' //添加\n    }\n}\n\n\nallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://jitpack.io' }  //添加\n\t\t}\n\t}\n```\n```\n//app目录下build.gradle\napply plugin: 'android-aspectjx' //添加\ndependencies {\n    implementation 'com.github.liys666666:DoubleClick:V3.0.0'  //添加\n}\n```\n如果不需要额外处理的话, 到这里就结束了, 同一个按钮点击, 默认最小间隔时间是500毫秒.\n\n**2.添加自定义属性:**\n```\npublic class AppApplication extends Application{\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        DoubleClickHelper\n                .getInstance()\n                .delayTime(500)  //间隔时间\n                .addAnnotationClass(UnifiedDoubleClick.class) //自定义属性, 可叠加\n                .addAnnotationClass(UnifiedDoubleClick2.class);\n    }\n}\n```\n\n```\npublic interface UnifiedDoubleClick{ //用户自定义接口\n//    >>>>>>>>>>>>>>>>>>>屏蔽DoubleClick的Activity>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n//    @ACancelActivity(activitys = {\n//            MainActivity.class,\n//    })\n//    void cancelActivity();\n\n\n//    >>>>>>>>>>>>>>>>>>>单个view处理>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n    @AAddDoubleClick(activity = MainActivity.class,\n            addIds = {R.id.btn1, R.id.btn2},\n            times = {0, 2000})  //点击的间隔时间\n    void mainActivity();\n\n//    >>>>>>>>>>>>>>>>>插入自定义clickListener>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n    @AClickListener(activity = MainActivity.class,\n            lisenner = LoginClickListener.class, //自定义clickListener\n            ids = {R.id.btn2})\n    void interceptMain();\n}\n```\n\n\n```\npublic class LoginClickListener implements IOnClickListener {\n\n    public static boolean isLogin = false;\n\n    @Override\n    public boolean isNext(View v) {\n        //判断登录逻辑\n        if(!isLogin){\n            LogUtil.d(\"未登录\");\n            Toast.makeText(v.getContext(), \"未登录\", Toast.LENGTH_SHORT).show();\n        }\n        return isLogin;\n    }\n\n\n    @Override\n    public void after(View view) {\n        //执行click后\n    }\n\n}\n\n```\n\n**扩展---可调用方法**\t\n```\nDoubleClickHelper.openAll(); //开启\nDoubleClickHelper.closeAll(); //关闭\n\n//(可选)用hook方式处理单个view, 时间会和上面的时间叠加, 一般使用场景: Activity只有个别按钮需要doubleClick\nDoubleClickHelper.hookView(View view, long delayTime); \n```\n\n\n# 三.历史版本:\n**V3.0.0:**\t\n使用AOP的方式处理, 使用方式和2.0基本一样, 比2.0的方式性能更好.\n\n[V2.0版本](https://github.com/liys666666/DoubleClick/blob/master/README2.0.6.md).\n\n[V1.0版本](https://github.com/liys666666/DoubleClick/blob/master/README1.0.4.md)\n\n* 如果框架中存在不足或者有什么建议, 欢迎指出, 我这边会尽快处理, 让框架更完善, 希望这个框架能帮助更多人, 如果觉得好用, 欢迎star.\n\n"
  },
  {
    "path": "README1.0.4.md",
    "content": "# DoubleClick\n# 一. 基本使用\n框架主要有两个功能(基本用法): \n\n**1. 无入侵解决按钮重复点击.** [使用方法](https://www.jianshu.com/p/7f3e5c8b8643)\n\n**2. onClick重复逻辑统一处理.** [使用方法](https://www.jianshu.com/p/b4038a2d68eb)\n\n**① 导入框架**\n```\n//项目根目录下,build.gradle\nallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://jitpack.io' }  //添加\n\t\t}\n\t}\n```\n```\n//app目录下build.gradle\ndependencies {\n    implementation 'com.github.liys666666:DoubleClick:V1.0.4'  //添加\n}\n```\n**② 自定义的Application初始化即可**\n```\npublic class AppApplication extends Application{\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        ViewDoubleHelper.init(this); //默认时间：1秒\n//        ViewDoubleHelper.init(this, 2000); //自定义点击间隔时间(单位：毫秒)\n    }\n}\n```\n\n\n# 二.扩展:\n**V.1.0.2(包含)以上**\n\n1. onClick重复逻辑统一处理--添加新写法(可选):\n\n建议先看基本用法: [onClick重复逻辑统一处理](https://www.jianshu.com/p/b4038a2d68eb)\n\n```\npublic class MainActivity extends AppCompatActivity implements IAddCustomHookClick{\n\t    @Override\n\t    public List<CustomHookBean> getCustomHookList() {\n\t\tint[] ids = {R.id.btn1, R.id.btn2}; //需要处理的id\n\t\tList<CustomHookBean> list = new ArrayList<>();\n\t\tfor (int i = 0; i < ids.length; i++) { //添加\n\t\t    list.add(new CustomHookBean(ids[i], new LoginClickListener()));\n\t\t}\n\t\treturn list;\n\t    }\n}\n```\n\n2. 如果有更好的具体实现方法, 也可以自己实现, 具体做法, 其它不变, 在AppApplication是添加:\n```\n        //连续重复点击多次, 自定义具体实现\n//        ViewDoubleHelper.setIViewDoubleClick(new IViewDoubleClick() {\n//            @Override\n//            public void hookActivityViews(Activity activity, long delayTime) { \n//\t\t\t//hook  Activity内所有View\n//            }\n//\n//            @Override\n//            public void hookResView(Activity activity, int viewResId, long delayTime) {\n//\t\t\t//根据ViewId hook对应的View  \n//            }\n//\n//            @Override\n//            public void hookView(Activity activity, View view, long delayTime) {\n//\t\t\t//hook对应的View\n//            }\n//        });\n\n\n        //onClick重复逻辑统一处理: 自定义具体实现\n//        ViewDoubleHelper.setICustomHookClick(new ICustomHookClick() {\n//            @Override\n//            public void hookResView(Activity activity, int viewResId, IOnClickListener iClickListener) {\n//\n//            }\n//\n//            @Override\n//            public void hookView(Activity activity, View view, IOnClickListener iClickListener) {\n//\n//            }\n//        });\n```\n\n# 三.历史版本:\n**V1.0.4:**\t修复:版本兼容问题\n\n**V1.0.3:**\t修复bug: 每次pause返回, 都重复hookView\n\n\n**V1.0.2:**\n* ①.onClick重复逻辑统一处理使用IAddCustomHookClick处理, 添加自由扩展实现.\n* ②. 新增方法 ViewDoubleHelper.setIViewDoubleClick(IViewDoubleClick), ViewDoubleHelper.setICustomHookClick(ICustomHookClick);\n\n\n\n**V1.0.1:** \t新增功能: onClick重复逻辑统一处理\n\n\n\n**V1.0.0:** \t新增功能: 无入侵解决按钮重复点击\n"
  },
  {
    "path": "README2.0.6.md",
    "content": "# DoubleClick\nV2.0 的使用方法: \n\n简书: https://www.jianshu.com/p/df0ef3866cc1\nCSDN: https://blog.csdn.net/qq_33199629/article/details/101563232\n\n**简单介绍:**\n```\n//项目根目录下,build.gradle\nallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://jitpack.io' }  //添加\n\t\t}\n\t}\n```\n```\n//app目录下build.gradle\ndependencies {\n    implementation 'com.github.liys666666:DoubleClick:V2.0.6'  //添加\n}\n```\n```\npublic class AppApplication extends Application{\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n//        ViewDoubleHelper.init(this); //默认时间：1秒\n//        ViewDoubleHelper.init(this, 500); //自定义点击间隔时间(单位：毫秒)\n          ViewDoubleHelper.init(this, 1000, UnifiedDoubleClick.class); //自定义点击间隔时间(单位：毫秒)\n          \n          //单独设置, 不同的AnnotationClass可叠加(V2.0.5版本后可用)\n          ViewDoubleHelper.addAnnotationClass(UnifiedDoubleClick2.class);\n    }\n}\n```\n\n```\npublic interface UnifiedDoubleClick{ //用户自定义接口\n//    >>>>>>>>>>>>>>>>>>>屏蔽DoubleClick的Activity>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n//    @ACancelActivity(activitys = {\n//            MainActivity.class,\n//    })\n//    void cancelActivity();\n\n\n//    >>>>>>>>>>>>>>>>>>>单个view处理>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n    @AAddDoubleClick(activity = MainActivity.class,\n            addIds = {R.id.btn1, R.id.btn2},\n            times = {0, 2000})  //点击的间隔时间\n    void mainActivity();\n\n//    >>>>>>>>>>>>>>>>>插入自定义clickListener>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n    @AClickListener(activity = MainActivity.class,\n            lisenner = LoginClickListener.class, //自定义clickListener\n            ids = {R.id.btn2})\n    void interceptMain();\n}\n```\n\n```\npublic class LoginClickListener extends BaseClickListener{\n\n    public static boolean isLogin = false; //模拟是否登陆\n\n    @Override\n    public boolean isNext(View v) {\n        //判断登录逻辑 (onClick前执行)\n\n        return isLogin;  //true继续执行onClick,  false不再执行\n    }\n\n    @Override\n    public void after(View view) {\n        //onClick后 执行\n    }\n\n}\n```\n\n**扩展---可调用方法**\t\n```\n//hook单个view(子View不会跟着变化) 例如: Recyclerview使用的话, itemView是不起作用的\nViewDoubleHelper.hookView(View view, long delayTime); \n\nhook单个view(所有子View会跟着一起变化) 例如: Recyclerview使用的话, itemView以及子控件全部有用\nViewDoubleHelper.hookChildViews(View view, long delayTime); \n\n//重新hook当前Activity\nViewDoubleHelper.hookActivity();\n\n//如果你有更好的实现方法, 也可以自己实现\nViewDoubleHelper.addIViewDoubleClick(IViewDoubleClick iHookView);\n```\n\n\n# 三.历史版本:\n**V2.0.6:**\t\n* 修复:\n* ViewDoubleHelper.hookChildViews() 不起作用\n* ViewDoubleHelper.hookActivity()在onResume()前 调用不起作用.\n\n**V2.0.5:**\t\n* 优化: 问题描述:原来的注解只能在Application初始化时传一个类进去;\n* 问题1: 如果注解使用过多, 所有的注解都写在一个类里面, 不好管理.\n* 问题2: 在组件化架构中, 有个id无法在Application中获取.\n* 解决办法: 使用新增方法 ViewDoubleHelper.addAnnotationClass(annotationClass); 可设置多个\n\n**V2.0.4:**\t\n* 修复: 动态加载View不起作用(包括自定义View, Fragment, RecyclerView中不起作用等等)。\n\n**V2.0.2:**\t\n* 1. 修复兼容问题：注解android9.0不起作用.\n* 2. 手动重新hookActivity\n\n**V2.0.1:**     \n* 1. 完全不需要在具体的Activity和Fragment加代码.\n* 2. 是否屏蔽hook、单个View处理, 自定义拦截器，全部使用接口注解处理.\n* 3. 单个View处理、自定义拦截器，兼容Fragment.\n\n[V1.0版本](https://github.com/liys666666/DoubleClick/blob/master/README1.0.4.md)\n\n* 如果框架中存在不足或者有什么建议, 欢迎指出, 我这边会尽快处理, 让框架更完善, 希望这个框架能帮助更多人, 如果觉得好用, 欢迎star.\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'android-aspectjx'\n\nandroid {\n    compileSdkVersion 28\n    defaultConfig {\n        applicationId \"com.liys.doubleclickdemo\"\n        minSdkVersion 19\n        targetSdkVersion 28\n        versionCode 6\n        versionName \"3.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\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    implementation 'com.android.support:appcompat-v7:28.0.0'\n    implementation 'com.android.support.constraint:constraint-layout:1.1.3'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.2'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'\n    implementation project(':doubleclicklibrary')\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\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/com/liys/doubleclickdemo/ExampleInstrumentedTest.java",
    "content": "package com.liys.doubleclickdemo;\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 * Instrumented 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() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.liys.doubleclickdemo\", 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    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.liys.doubleclickdemo\">\n\n    <application\n        android:name=\".AppApplication\"\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        tools:ignore=\"GoogleAppIndexingWarning\">\n        <activity android:name=\".MainActivity\">\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        <activity android:name=\".fragment.MainActivity2\"/>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/AppApplication.java",
    "content": "package com.liys.doubleclickdemo;\n\nimport android.app.Application;\n\nimport com.liys.doubleclicklibrary.DoubleClickHelper;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/22 11:01\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/22 11:01\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class AppApplication extends Application{\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        DoubleClickHelper\n                .getInstance()\n                .delayTime(500)  //间隔时间\n                .addAnnotationClass(UnifiedDoubleClick.class)\n                .addAnnotationClass(UnifiedDoubleClick2.class);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/LogUtil.java",
    "content": "package com.liys.doubleclickdemo;\n\nimport android.util.Log;\n\n/**\n * @Description: 输出日志\n * @Author: liys\n * @CreateDate: 2019/5/28 10:55\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/5/28 10:55\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class LogUtil {\n    //是否需要打印信息\n    public static boolean isDebug = true;\n    //打印信息的标识\n    public static final String TAG = \"66\";\n\n    public static void e(String msg) {\n        if (isDebug) Log.e(TAG, msg);\n    }\n\n    public static void d(String msg) {\n        if (isDebug) Log.d(TAG, msg);\n    }\n\n    public static void i(String msg) {\n        if (isDebug) Log.i(TAG, msg);\n    }\n\n    public static void w(String msg) {\n        if (isDebug) Log.w(TAG, msg);\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/LoginClickListener.java",
    "content": "package com.liys.doubleclickdemo;\n\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.liys.doubleclicklibrary.listener.IOnClickListener;\n\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/22 15:52\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/11/23 22:52\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class LoginClickListener implements IOnClickListener {\n\n    public static boolean isLogin = false;\n\n    @Override\n    public boolean isNext(View v) {\n        //判断登录逻辑\n        if(!isLogin){\n            LogUtil.d(\"未登录\");\n            Toast.makeText(v.getContext(), \"未登录\", Toast.LENGTH_SHORT).show();\n        }\n        return isLogin;\n    }\n\n\n    @Override\n    public void after(View view) {\n        //执行click后\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/MainActivity.java",
    "content": "package com.liys.doubleclickdemo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.liys.doubleclickdemo.fragment.MainActivity2;\n\npublic class MainActivity extends AppCompatActivity implements View.OnClickListener{\n\n    TextView tvHint;\n    long num = 0;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        tvHint = findViewById(R.id.tv_hint);\n\n        findViewById(R.id.btn1).setOnClickListener(this);\n        findViewById(R.id.btn2).setOnClickListener(this);\n        findViewById(R.id.login).setOnClickListener(this);\n        findViewById(R.id.logout).setOnClickListener(this);\n        findViewById(R.id.start).setOnClickListener(this);\n\n//        Log.d(\"66\", \"btn1=\"+R.id.btn1);\n//        Log.d(\"66\", \"onCreate\");\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()){\n            case R.id.btn1:\n                num++;\n                tvHint.setText(num+\"\");\n                break;\n            case R.id.btn2:\n                num--;\n                tvHint.setText(num+\"\");\n                break;\n            case R.id.login:\n                LoginClickListener.isLogin = true;\n                Toast.makeText(this, \"登录成功\", Toast.LENGTH_SHORT).show();\n                break;\n            case R.id.logout:\n                LoginClickListener.isLogin = false;\n                Toast.makeText(this, \"取消登录\", Toast.LENGTH_SHORT).show();\n                break;\n            case R.id.start:\n                startActivity(new Intent(this, MainActivity2.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/UnifiedDoubleClick.java",
    "content": "package com.liys.doubleclickdemo;\n\nimport com.liys.doubleclickdemo.fragment.MainActivity2;\nimport com.liys.doubleclicklibrary.annotation.AAddDoubleClick;\nimport com.liys.doubleclicklibrary.annotation.AClickListener;\n\n/**\n * @Description: 统一处理 DoubleClick\n * @Author: liys\n * @CreateDate: 2019/8/26 16:46\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/26 16:46\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic interface UnifiedDoubleClick{\n\n\n//    >>>>>>>>>>>>>>>>>>>屏蔽DoubleClick的Activity>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n//    @ACancelActivity(activitys = {\n//            MainActivity.class,\n//    })\n//    void cancelActivity();\n\n\n//    >>>>>>>>>>>>>>>>>>>单个view处理>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n//    @AAddDoubleClick(activity = MainActivity.class,\n//            addIds = {R.id.btn1, R.id.btn2},\n//            times = {2000, 0})\n//    void mainActivity();\n\n\n    @AAddDoubleClick(activity = MainActivity2.class,\n            addIds = {R.id.btn_add_fragment, R.id.btn_fragment},\n            times = {2000, 2000})\n    void mainActivity2();\n\n\n\n//    >>>>>>>>>>>>>>>>>自定义click拦截器>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n    @AClickListener(activity = MainActivity.class,\n            lisenner = LoginClickListener.class,\n            ids = {R.id.btn2})\n    void interceptMain();\n\n    @AClickListener(activity = MainActivity2.class,\n            lisenner = LoginClickListener.class,\n            ids = {R.id.btn_add_fragment, R.id.btn_fragment})\n    void interceptMain2();\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/UnifiedDoubleClick2.java",
    "content": "package com.liys.doubleclickdemo;\n\nimport com.liys.doubleclicklibrary.annotation.ACancelActivity;\n\n/**\n * @Description: 统一处理 DoubleClick\n * @Author: liys\n * @CreateDate: 2019/8/26 16:46\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/26 16:46\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic interface UnifiedDoubleClick2 {\n\n\n//    >>>>>>>>>>>>>>>>>>>屏蔽DoubleClick的Activity>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n    @ACancelActivity(activitys = {\n            MainActivity.class,\n    })\n    void cancelActivity();\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/fragment/MainActivity2.java",
    "content": "package com.liys.doubleclickdemo.fragment;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentPagerAdapter;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v4.view.ViewPager;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.TextView;\n\nimport com.liys.doubleclickdemo.R;\n\npublic class MainActivity2 extends AppCompatActivity implements OnClickListener{\n\n    ViewPager viewPage;\n\n    TextView tvNum;\n    int num = 0;\n    MyFragment myFragment = new MyFragment();\n    MyFragment2 myFragment2 = new MyFragment2();\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main2);\n\n        viewPage = findViewById(R.id.viewPage);\n\n        tvNum = findViewById(R.id.tv_num);\n        findViewById(R.id.btn_add_fragment).setOnClickListener(this);\n        findViewById(R.id.btn_add_fragment2).setOnClickListener(this);\n        findViewById(R.id.btn_add).setOnClickListener(this);\n\n        viewPage.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {\n            @Override\n            public Fragment getItem(int i) {\n                if(i==0){\n                    return myFragment;\n                }\n                return myFragment2;\n            }\n\n            @Override\n            public int getCount() {\n                return 2;\n            }\n        });\n    }\n\n    Fragment curFragment;\n    @Override\n    public void onClick(View v) {\n        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n        switch (v.getId()){\n            case R.id.btn_add_fragment:\n//                transaction.replace(R.id.myFragment, myFragment);\n//                transaction.commit();\n\n                if(myFragment.isAdded()){\n                    transaction\n                            .hide(myFragment2)\n                            .show(myFragment)\n                            .commit();\n                }else{\n                    transaction\n                            .hide(myFragment2)\n                            .add(R.id.myFragment, myFragment)\n                            .show(myFragment)\n                            .commit();\n                }\n                break;\n            case R.id.btn_add_fragment2:\n                if(myFragment2.isAdded()){\n                    transaction\n                            .hide(myFragment)\n                            .show(myFragment2)\n                            .commit();\n                }else{\n                    transaction\n                            .hide(myFragment)\n                            .add(R.id.myFragment, myFragment2)\n                            .show(myFragment2)\n                            .commit();\n                }\n                break;\n            case R.id.btn_fragment:\n                num--;\n                tvNum.setText(num+\"\");\n                break;\n            case R.id.btn_add:\n                num++;\n                tvNum.setText(num+\"\");\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/fragment/MyFragment.java",
    "content": "package com.liys.doubleclickdemo.fragment;\n\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.liys.doubleclickdemo.R;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/28 13:45\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/28 13:45\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class MyFragment extends Fragment {\n\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.fragment_my, container, false);\n        view.findViewById(R.id.btn_fragment).setOnClickListener((View.OnClickListener)getActivity());\n        return view;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liys/doubleclickdemo/fragment/MyFragment2.java",
    "content": "package com.liys.doubleclickdemo.fragment;\n\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.liys.doubleclickdemo.R;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/28 13:45\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/28 13:45\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class MyFragment2 extends Fragment {\n\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.fragment_my2, container, false);\n        view.findViewById(R.id.btn_fragment).setOnClickListener((View.OnClickListener)getActivity());\n        return view;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#008577\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>\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    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".MainActivity\">\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n        <Button\n            android:id=\"@+id/btn1\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"按钮1\"/>\n        <Button\n            android:id=\"@+id/btn2\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"按钮2\"/>\n        <Button\n            android:id=\"@+id/login\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:tag=\"no\"\n            android:text=\"登录\"/>\n        <Button\n            android:id=\"@+id/logout\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:tag=\"no\"\n            android:text=\"取消登录\"/>\n    </LinearLayout>\n    <Button\n        android:id=\"@+id/start\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:tag=\"no\"\n        android:text=\"跳转\"/>\n    <TextView\n        android:id=\"@+id/tv_hint\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:textSize=\"100sp\"\n        android:text=\"0\"/>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".MainActivity\">\n\n    <Button\n        android:id=\"@+id/btn_add_fragment\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAllCaps=\"false\"\n        android:text=\"add_fragment\"/>\n    <Button\n        android:id=\"@+id/btn_add_fragment2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAllCaps=\"false\"\n        android:text=\"add_fragment2\"/>\n\n    <Button\n        android:id=\"@+id/btn_add\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAllCaps=\"false\"\n        android:text=\"activity++\"/>\n\n    <FrameLayout\n        android:id=\"@+id/myFragment\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/viewPage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"/>\n    <TextView\n        android:id=\"@+id/tv_num\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_horizontal\"\n        android:textSize=\"50sp\"\n        android:text=\"0\"/>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_my.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/colorPrimary\">\n    <Button\n        android:id=\"@+id/btn_fragment\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAllCaps=\"false\"\n        android:text=\"btn_fragment1\"/>\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"20dp\"\n        android:text=\"Fragment1\"/>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_my2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/colorPrimary\">\n    <Button\n        android:id=\"@+id/btn_fragment\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAllCaps=\"false\"\n        android:text=\"btn_fragment2\"/>\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"20dp\"\n        android:text=\"Fragment2\"/>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"colorPrimaryDark\">#00574B</color>\n    <color name=\"colorAccent\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">DoubleClickDemo</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/test/java/com/liys/doubleclickdemo/ExampleUnitTest.java",
    "content": "package com.liys.doubleclickdemo;\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() {\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    \n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.2.0'\n        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "doubleclicklibrary/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "doubleclicklibrary/build.gradle",
    "content": "apply plugin: 'com.android.library'\n//apply plugin: 'android-aspectjx'\n\nandroid {\n    compileSdkVersion 26\n\n\n\n    defaultConfig {\n        minSdkVersion 15\n        targetSdkVersion 26\n        versionCode 6\n        versionName \"3.0.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n\n    implementation 'com.android.support:appcompat-v7:26.1.0'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.2'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'\n\n//    api 'org.aspectj:aspectjrt:1.8.9'\n    implementation 'org.aspectj:aspectjrt:1.8.9'\n}\n"
  },
  {
    "path": "doubleclicklibrary/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\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": "doubleclicklibrary/src/androidTest/java/com/liys/doubleclicklibrary/ExampleInstrumentedTest.java",
    "content": "package com.liys.doubleclicklibrary;\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 * Instrumented 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() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.liys.doubleclicklibrary.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.liys.doubleclicklibrary\" />\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/DoubleClickHelper.java",
    "content": "package com.liys.doubleclicklibrary;\n\nimport android.view.View;\n\nimport com.liys.doubleclicklibrary.aspect.Attrs;\nimport com.liys.doubleclicklibrary.hook.BaseHookView;\nimport com.liys.doubleclicklibrary.hook.IHookView;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/11/20\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/11/20\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class DoubleClickHelper {\n\n    private static IHookView mIHookView;\n    private static DoubleClickHelper doubleClickHelper = new DoubleClickHelper();\n\n    public static DoubleClickHelper getInstance(){\n        return doubleClickHelper;\n    }\n\n    public DoubleClickHelper delayTime(long delayTime){\n        Attrs.delayTime = delayTime;\n        return this;\n    }\n\n    public DoubleClickHelper addAnnotationClass(Class annotationClass){\n        Attrs.addAnnotationClass(annotationClass);\n        return this;\n    }\n\n\n    public static void openAll(){\n        Attrs.isOpen = true;\n    }\n\n    public static void closeAll(){\n        Attrs.isOpen = false;\n    }\n\n    public static void hookView(final View view, final long delayTime){\n        if(mIHookView==null){\n            mIHookView = new BaseHookView();\n        }\n        view.post(new Runnable() {\n            @Override\n            public void run() {\n                mIHookView.hookView(view, delayTime);\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/annotation/AAddDoubleClick.java",
    "content": "package com.liys.doubleclicklibrary.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/27 12:19\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/27 12:19\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface AAddDoubleClick {\n\n    Class activity();\n    int[] addIds();\n    long[] times();\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/annotation/ACancelActivity.java",
    "content": "package com.liys.doubleclicklibrary.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/27 12:19\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/27 12:19\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface ACancelActivity {\n    Class[] activitys();\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/annotation/AClickListener.java",
    "content": "package com.liys.doubleclicklibrary.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/27 17:27\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/27 17:27\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface AClickListener {\n\n    Class activity();\n\n    Class lisenner();\n\n    int[] ids();\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/annotation/helper/AnnotationHelper.java",
    "content": "package com.liys.doubleclicklibrary.annotation.helper;\n\nimport com.liys.doubleclicklibrary.annotation.AAddDoubleClick;\nimport com.liys.doubleclicklibrary.annotation.ACancelActivity;\nimport com.liys.doubleclicklibrary.annotation.AClickListener;\n\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @Description: 解析注解\n * @Author: liys\n * @CreateDate: 2019/8/27 14:29\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/27 14:29\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class AnnotationHelper {\n\n    /**\n     * 获取ACancelActivity集合\n     * @param annotationClass\n     */\n    public static Map<Class, String> getACancelActivity(Class annotationClass){\n        Map<Class, String> classMap = new HashMap<>();\n        Method[] methods = annotationClass.getDeclaredMethods(); //解析方法上的注解\n        for(Method method : methods){\n            boolean methodHasAnno = method.isAnnotationPresent(ACancelActivity.class);\n            if(methodHasAnno){\n                ACancelActivity methodAnno = method.getAnnotation(ACancelActivity.class); //得到注解\n                Class[] clazzs = methodAnno.activitys();\n                for (int i = 0; i < clazzs.length; i++) {\n                    classMap.put(clazzs[i], clazzs[i].getName());\n                }\n                return classMap;\n            }\n        }\n        return classMap;\n    }\n\n\n    /**\n     * 获取AAddDoubleClick集合\n     * @param\n     */\n    public static Map<Class, Map<Integer, Long>> getAddDoubleClick(Class annotationClass){\n        Map<Class, Map<Integer, Long>> addViewMap = new HashMap<>();\n        Method[] methods = annotationClass.getDeclaredMethods(); //解析方法上的注解\n        for(Method method : methods){\n            boolean methodHasAnno = method.isAnnotationPresent(AAddDoubleClick.class);\n            if(methodHasAnno){\n                AAddDoubleClick methodAnno = method.getAnnotation(AAddDoubleClick.class); //得到注解\n                Class clazz = methodAnno.activity();\n                int[] ids = methodAnno.addIds();\n                long[] times = methodAnno.times();\n                Map<Integer, Long> idsMap = new HashMap<>();\n                for (int i = 0; i < ids.length; i++) {\n                    idsMap.put(ids[i], times[i]);\n                }\n                addViewMap.put(clazz, idsMap);\n            }\n        }\n        return addViewMap;\n    }\n\n\n    /**\n     *  获取AClickListener集合\n     * @param annotationClass\n     * @return\n     */\n    public static Map<Class, Map<Integer, Class>> getClickListener(Class annotationClass){\n        Map<Class, Map<Integer, Class>> viewListenerMap = new HashMap<>();\n        Method[] methods = annotationClass.getDeclaredMethods(); //解析方法上的注解\n        for(Method method : methods){\n            boolean methodHasAnno = method.isAnnotationPresent(AClickListener.class);\n            if(methodHasAnno){\n                AClickListener methodAnno = method.getAnnotation(AClickListener.class); //得到注解\n                Class activityClazz = methodAnno.activity();\n                Class lisennerClazz = methodAnno.lisenner();\n                int[] ids = methodAnno.ids();\n                Map<Integer, Class> idsMap = new HashMap<>();\n                for (int i = 0; i < ids.length; i++) {\n                    idsMap.put(ids[i], lisennerClazz);\n                }\n                viewListenerMap.put(activityClazz, idsMap);\n            }\n        }\n        return viewListenerMap;\n    }\n\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/aspect/AspectDoubleClick.java",
    "content": "package com.liys.doubleclicklibrary.aspect;\n\nimport android.view.View;\n\nimport com.liys.doubleclicklibrary.listener.IOnClickListener;\n\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\n\nimport java.util.Map;\n\n/**\n * @Description: AOP主要类\n * @Author: liys\n * @CreateDate: 2019/11/18 20:48\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/11/18 20:48\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\n@Aspect\npublic class AspectDoubleClick{\n\n    private IOnClickListener iOnClickListener = null;\n    private long lastTime; //上次间隔时间\n    private View lastView; //点击的view\n\n\n    @Around(\"execution(* android.view.View.OnClickListener.onClick(..))\")\n    public void onClickListener(ProceedingJoinPoint joinPoint) throws Throwable {\n        if(!Attrs.isOpen){ //未打开拦截\n            joinPoint.proceed();\n            return;\n        }\n\n        Object[] args = joinPoint.getArgs();\n        View view = (View)args[0];\n\n        if(view != lastView){ //不是同一个View直接过\n            iOnClickListener = null; //还原\n            setListenerAnnotation(view); //拦截信息\n            execution(joinPoint, view);\n            Attrs.annotationDelayTime = -1; //还原\n            setViewAnnotation(view); //View\n            lastView = view;\n            lastTime = System.currentTimeMillis();\n            return;\n        }\n\n        long delayTime = Attrs.delayTime; //默认值\n        if(Attrs.annotationDelayTime != -1){\n            delayTime = Attrs.annotationDelayTime;\n        }\n\n        //4.执行\n        if(System.currentTimeMillis()- lastTime >= delayTime){\n            execution(joinPoint, view);\n            lastTime = System.currentTimeMillis();\n            lastView = view;\n        }\n    }\n\n    //继续执行\n    private void execution(ProceedingJoinPoint joinPoint, View view){\n        try {\n            if(iOnClickListener == null){ //无拦截\n                    joinPoint.proceed();\n            }else{\n                if(iOnClickListener.isNext(view)){ //继续执行\n                    joinPoint.proceed();\n                    iOnClickListener.after(view);\n                }\n            }\n        } catch (Throwable throwable) {\n            throwable.printStackTrace();\n        }\n    }\n\n    //解析View注解信息\n    private void setViewAnnotation(View view){\n        Class activityClass = view.getContext().getClass();\n\n        //1.对应Activity取消的话\n        if(Attrs.mCancelClassMap.containsKey(activityClass)){ //取消\n            Attrs.annotationDelayTime = 0;\n        }\n\n        //2.单个View添加\n        if(Attrs.mAddViewMap.containsKey(activityClass)){\n            Map<Integer, Long> viewMap = Attrs.mAddViewMap.get(activityClass);\n            if(viewMap.containsKey(view.getId())){\n                Attrs.annotationDelayTime = viewMap.get(view.getId());\n            }\n        }\n    }\n\n    //解析Listener注解信息\n    private void setListenerAnnotation(View view) {\n        Class activityClass = view.getContext().getClass();\n        //3. onclick前后插入自定义方法\n        if (Attrs.mViewListenerMap.containsKey(activityClass)) {\n            Map<Integer, Class> viewMap = Attrs.mViewListenerMap.get(activityClass);\n            if (viewMap.containsKey(view.getId())) {\n                try {\n                    Object obj = viewMap.get(view.getId()).newInstance();\n                    if (obj instanceof IOnClickListener) {\n                        iOnClickListener = (IOnClickListener) obj;\n                    }\n                } catch (InstantiationException e) {\n                    e.printStackTrace();\n                } catch (IllegalAccessException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/aspect/Attrs.java",
    "content": "package com.liys.doubleclicklibrary.aspect;\n\nimport com.liys.doubleclicklibrary.annotation.helper.AnnotationHelper;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @Description: 传递进来的属性\n * @Author: liys\n * @CreateDate: 2019/11/23 21:42\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/11/23 21:42\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\n public class Attrs {\n\n    public static boolean isOpen = true; //是否打开\n    public static long delayTime = 500; //全局间隔时间\n    public static long annotationDelayTime = -1; //注解里面设置的时间, 如果没有设置,设为-1\n\n    private  static List<Class> mAnnotationClassList = new ArrayList<>(); //注解类--集合\n\n    public static Map<Class, String> mCancelClassMap = new HashMap<>(); //取消的Activity\n    public static Map<Class, Map<Integer, Long>> mAddViewMap = new HashMap<>(); //单个添加\n    public static Map<Class, Map<Integer, Class>> mViewListenerMap = new HashMap<>(); //拦截 并自定义click\n\n    public static void addAnnotationClass(Class annotationClass) {\n        if(annotationClass == null ){\n            return;\n        }\n        if(!mAnnotationClassList.contains(annotationClass)){ //添加注解类信息\n            mAnnotationClassList.add(annotationClass);\n            mCancelClassMap.putAll(AnnotationHelper.getACancelActivity(annotationClass));\n            mAddViewMap.putAll(AnnotationHelper.getAddDoubleClick(annotationClass));\n            mViewListenerMap.putAll(AnnotationHelper.getClickListener(annotationClass));\n        }\n    }\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/hook/BaseHookView.java",
    "content": "package com.liys.doubleclicklibrary.hook;\n\nimport android.annotation.SuppressLint;\nimport android.view.View;\n\nimport com.liys.doubleclicklibrary.listener.IOnClickListener;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/26 17:24\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/26 17:24\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class BaseHookView implements IHookView {\n\n\n    /**\n     * hook点击事件\n     * @param view\n     * @param delayTime\n     * @param iOnClickListener 替换成自定义监听器\n     */\n    @Override\n    public void hookView(View view, long delayTime) {\n        try {\n            Class viewClazz = Class.forName(\"android.view.View\");\n            //事件监听器都是这个实例保存的\n            Method listenerInfoMethod = viewClazz.getDeclaredMethod(\"getListenerInfo\");\n            if (!listenerInfoMethod.isAccessible()) {\n                listenerInfoMethod.setAccessible(true);\n            }\n            Object listenerInfoObj = listenerInfoMethod.invoke(view);\n\n            @SuppressLint(\"PrivateApi\")\n            Class listenerInfoClazz = Class.forName(\"android.view.View$ListenerInfo\");\n\n            Field onClickListenerField = listenerInfoClazz.getDeclaredField(\"mOnClickListener\");\n            //修改修饰符带来不能访问的问题\n            if (!onClickListenerField.isAccessible()) {\n                onClickListenerField.setAccessible(true);\n            }\n            View.OnClickListener mOnClickListener = (View.OnClickListener) onClickListenerField.get(listenerInfoObj);\n            HookOnClickListener hookOnClickListener = new HookOnClickListener(delayTime);\n            if(!(mOnClickListener instanceof HookOnClickListener)) { //没有hook过\n                hookOnClickListener.setOnclickListener(mOnClickListener);\n            }\n            //更换成自己的点击事件\n            onClickListenerField.set(listenerInfoObj, hookOnClickListener);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/hook/HookOnClickListener.java",
    "content": "package com.liys.doubleclicklibrary.hook;\n\nimport android.view.View;\n\nimport java.util.Calendar;\n\n/**\n * @Description: 默认事件监听器\n * @Author: liys\n * @CreateDate: 2019/8/22 10:25\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/22 10:25\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic class HookOnClickListener implements View.OnClickListener{\n\n    private long min_click_delay_time = 500; //点击最小间隔时间\n    private long lastClickTime = 0;\n    private View.OnClickListener onClickListener;\n\n    public HookOnClickListener() {}\n\n    public HookOnClickListener(long min_click_delay_time) {\n        this.min_click_delay_time = min_click_delay_time;\n    }\n\n    public void setOnclickListener(View.OnClickListener onClickListener) {\n        this.onClickListener = onClickListener;\n    }\n\n\n    @Override\n    public void onClick(View v) {\n        long currentTime = Calendar.getInstance().getTimeInMillis();\n        if (currentTime - lastClickTime > min_click_delay_time) {\n            onClickListener.onClick(v);\n            lastClickTime = currentTime;\n        }\n    }\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/hook/IHookView.java",
    "content": "package com.liys.doubleclicklibrary.hook;\n\nimport android.view.View;\n\n/**\n * @Description:\n * @Author: liys\n * @CreateDate: 2019/8/22 11:46\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/8/22 11:46\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic interface IHookView {\n\n    /**\n     * hook单个View\n     * @param view  需要hook的view\n     * @param delayTime 间隔时间\n     */\n    void hookView(final View view, final long delayTime);\n\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/java/com/liys/doubleclicklibrary/listener/IOnClickListener.java",
    "content": "package com.liys.doubleclicklibrary.listener;\n\nimport android.view.View;\n\n/**\n * @Description: 自定义拦截onclick\n * @Author: liys\n * @CreateDate: 2019/11/23 21:23\n * @UpdateUser: 更新者\n * @UpdateDate: 2019/11/23 10:46\n * @UpdateRemark: 更新说明\n * @Version: 1.0\n */\npublic interface IOnClickListener {\n\n    /**\n     * 是否继续往下执行(click前执行)\n     * @return\n     */\n    boolean isNext(View view);\n\n    /**\n     * 执行完click之后\n     * @param view\n     */\n    void after(View view);\n\n}\n"
  },
  {
    "path": "doubleclicklibrary/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">DoubleClickLibrary</string>\n</resources>\n"
  },
  {
    "path": "doubleclicklibrary/src/test/java/com/liys/doubleclicklibrary/ExampleUnitTest.java",
    "content": "package com.liys.doubleclicklibrary;\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() {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.6-all.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\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# 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\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\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\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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\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\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\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\" -a \"$nonstop\" = \"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# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\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\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\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\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 Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_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=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':doubleclicklibrary'\n"
  }
]