diff --git a/CHANGELOG.md b/CHANGELOG.md index 07fad4777f..73e8145bf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,35 @@ -* `20/04/26` [fix] Utils#init fit tinker. Publish 1.28.3. +* `22/10/15` [add] Fix some issue. Publish v1.31.1 +* `21/12/06` [add] Publish v1.31.0 +* `21/05/13` [add] Support publish mavenCentral. +* `21/02/22` [add] Fix ToastUtils rtl bug. Publish v1.30.6. +* `20/11/16` [add] Add ImageUtils#save2Album support param of dirName. +* `20/11/13` [add] Fix MessengerUtils ANR. Add NetworkUtils#getWifiScanResult, [add|remove]OnWifiChangedConsumer. Publish v1.30.5. +* `20/10/29` [add] Fix MessengerUtils startService IllegalStateException. Publish v1.30.4. +* `20/10/28` [add] Fix BusUtils ConcurrentModificationException. Publish v1.30.3. +* `20/10/27` [add] Fix AppUtils#getAppSignatures. Add DeviceUtils#isDevelopmentSettingsEnabled. Publish v1.30.2. +* `20/10/26` [add] Fix AppUtils#isAppForeground. Publish v1.30.1. +* `20/10/24` [add] Publish v1.30.0. +* `20/10/23` [fix] LanguageUtils crash on some device. +* `20/10/21` [add] LogUtils.Config#setOnConsoleOutputListener, setOnFileOutputListener, addFileExtraHead. LogUtils.getCurrentLogFilePath. +* `20/10/20` [opt] ToastUtils. +* `20/10/12` [add] PermissionUtils#explain. +* `20/10/10` [add] ClipboardUtils. +* `20/10/08` [add] VolumeUtils. +* `20/09/06` [add] DebouncingUtils#isValid. +* `20/09/04` [fix] ToastUtils adapt SDK 30. +* `20/05/28` [fix] IntentUtils#getInstallAppIntent file exist wrong. Publish v1.29.0. +* `20/05/23` [fix] BusUtils#postSticky times not right. Publish v1.28.6. +* `20/05/22` [add] IntentUtils#getInstallAppIntent support Uri param. +* `20/05/21` [add] Publish bus plugin v2.6. Publish api plugin v1.4. Publish. Publish v1.28.5. +* `20/05/19` [fix] FileUtils#copyOrMoveDird NPE. +* `20/05/18` [add] IntentUtils#getLaunchAppDetailsSettingsIntent support isNewTask. +* `20/05/17` [add] ImageUtils#save2Album, NetworkUtils#getSSID, UtilsTransActivity4MainProcess. +* `20/05/03` [add] Publish bus plugin v2.5. Publish api plugin v1.3. Publish. Publish v1.28.4. +* `20/04/30` [add] BaseItem support partialUpdate. +* `20/04/29` [add] Publish plugin lib com.blankj:base-transform:1.0. +* `20/04/28` [fix] LanguageUtils#applyLanguage. +* `20/04/27` [fix] BarUtils#isNavBarVisible. +* `20/04/26` [fix] Utils#init fit tinker. Publish v1.28.3. * `20/04/25` [fix] UriUtils#uri2File Unknown URI. Publish 1.28.2. * `20/04/24` [add] SnackbarUtils support show on the top; UriUtils#uri2InputStream. * `20/04/23` [fix] UriUtils#uri2File not support HW; TransActivity crash below 21. @@ -80,6 +111,7 @@ * `19/04/24` [upd] The swipe panel. * `19/03/17` [fix] The ugly UI. * `19/03/14` [fix] AdaptScreenUtils didn't work on some HaWei tablet. +* `19/03/09` [fix] UriUtils#uri2File. * `19/03/08` [add] LogUtils support multi process. Publish v1.23.7. * `19/03/02` [fix] LogUtils#file. * `19/02/28` [fix] ImageUtils#calculateInSampleSize. Publish v1.23.6. diff --git a/README-CN.md b/README-CN.md index 32a5a0ac17..5c85dca1fe 100644 --- a/README-CN.md +++ b/README-CN.md @@ -42,9 +42,7 @@ ## 打个小广告 -欢迎加入我的知识星球「**[基你太美](https://t.zsxq.com/FmeqfYF)**」,我会在星球中分享 [AucFrame](https://blankj.com/2019/07/22/auc-frame/) 框架、大厂面经、[AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode) 更详尽的说明...一切我所了解的知识,你可以通过支付进入我的星球「**[基你太美](https://t.zsxq.com/FmeqfYF)**」进行体验,加入后优先观看星球中精华的部分,如果觉得星球的内容对自身没有收益,你可以自行申请退款退出星球,也没必要加我好友;**如果你已确定要留在我的星球,可以通过扫描如下二维码(备注:基你太美+你的星球昵称)加我个人微信,方便我后续拉你进群(PS:进得越早价格越便宜)。** - - +欢迎加入我的小专栏「**[基你太美](https://xiaozhuanlan.com/Blankj)**」一起学习。 [logo]: https://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/logo.png diff --git a/README.md b/README.md index e0df3165eb..9ae668e26e 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,7 @@ If this project helps you a lot and you want to support the project's developmen ## 打个小广告 -欢迎加入我的知识星球「**[基你太美](https://t.zsxq.com/FmeqfYF)**」,我会在星球中分享 [AucFrame](https://blankj.com/2019/07/22/auc-frame/) 框架、大厂面经、[AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode) 更详尽的说明...一切我所了解的知识,你可以通过支付进入我的星球「**[基你太美](https://t.zsxq.com/FmeqfYF)**」进行体验,加入后优先观看星球中精华的部分,如果觉得星球的内容对自身没有收益,你可以自行申请退款退出星球,也没必要加我好友;**如果你已确定要留在我的星球,可以通过扫描如下二维码(备注:基你太美)加我个人微信,发送给我你的星球 ID,方便我后续拉你进群(PS:进得越早价格越便宜)。** - - +欢迎加入我的小专栏「**[基你太美](https://xiaozhuanlan.com/Blankj)**」一起学习。 [logo]: https://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/logo.png diff --git a/art/wechat.png b/art/wechat.png deleted file mode 100644 index e166a4783f..0000000000 Binary files a/art/wechat.png and /dev/null differ diff --git a/build.gradle b/build.gradle index 24c3b741e7..e0f0f36c87 100644 --- a/build.gradle +++ b/build.gradle @@ -2,27 +2,25 @@ buildscript { ConfigUtils.init(gradle) repositories { - // use for debug plugin local - if (Config.depConfig.plugin_bus.useLocal || Config.depConfig.plugin_api.useLocal) { - maven() { - url new File("mavenLocal") - } - } + mavenLocal() google() + mavenCentral() jcenter() } dependencies { for (def entrySet : ConfigUtils.getApplyPlugins().entrySet()) { - classpath entrySet.value.dep + classpath entrySet.value.path } } } allprojects { repositories { + mavenLocal() maven { url "https://jitpack.io/" } google() + mavenCentral() jcenter() } @@ -30,8 +28,8 @@ allprojects { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' resolutionStrategy.eachDependency { - if (it.requested.group == 'com.android.support' - && !it.requested.name.contains('multidex')) { + if (it.requested.group == 'com.android.support' && !it.requested.name.contains( + 'multidex')) { it.useVersion Config.supportVersion } } diff --git a/buildApp.gradle b/buildApp.gradle index f8b40c95b5..93f0b9b1d4 100644 --- a/buildApp.gradle +++ b/buildApp.gradle @@ -1,53 +1,44 @@ +apply plugin: "com.android.application" + apply { - plugin "com.android.application" - plugin "kotlin-android" - plugin "kotlin-android-extensions" - if (Config.depConfig.plugin_api.isApply) { - plugin Config.depConfig.plugin_api.pluginId + from "${rootDir.path}/buildCommon.gradle" + from "${rootDir.path}/config/flavor.gradle" + if (Config.plugins.plugin_api.isApply) { + plugin Config.plugins.plugin_api.id } - if (Config.depConfig.plugin_bus.isApply) { - plugin Config.depConfig.plugin_bus.pluginId + if (Config.plugins.plugin_bus.isApply) { + plugin Config.plugins.plugin_bus.id } } configSigning() configApkName() -if (Config.depConfig.plugin_bus.isApply) { - bus { - onlyScanLibRegex = '^([:]|(com\\.blankj)).+$' - } -} - -if (Config.depConfig.plugin_api.isApply) { - api { - onlyScanLibRegex = '^([:]|(com\\.blankj)).+$' - } -} +//if (PluginConfig.plugin_bus.isApply) { +// bus { +// onlyScanLibRegex = '^([:]|(com\\.blankj)).+$' +// } +//} +// +//if (PluginConfig.plugin_api.isApply) { +// api { +// onlyScanLibRegex = '^([:]|(com\\.blankj)).+$' +// } +//} android { - compileSdkVersion Config.compileSdkVersion defaultConfig { - minSdkVersion Config.minSdkVersion - versionCode Config.versionCode - versionName Config.versionName applicationId Config.applicationId + suffix targetSdkVersion Config.targetSdkVersion multiDexEnabled true } buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - applicationIdSuffix ".debug" - resValue "string", "app_name", Config.appName + suffix + ".debug" - } + debug {} release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - resValue "string", "app_name", Config.appName + suffix } } @@ -61,29 +52,42 @@ android { maxProcessCount 8 dexInProcess = true } -} + productFlavors { + dev { + applicationIdSuffix ".dev" + versionNameSuffix "-dev" + resValue "string", "app_name", Config.appName + suffix + "-dev" + } + + production { + resValue "string", "app_name", Config.appName + suffix + } + } +} dependencies { // LeakCanary - debugImplementation Config.depConfig.leakcanary_android.dep + debugImplementation Config.libs.leakcanary.path - debugImplementation Config.depConfig.lib_utildebug.dep - releaseImplementation Config.depConfig.lib_utildebug_no_op.dep + debugImplementation Config.modules.lib_utildebug.dep + releaseImplementation Config.modules.lib_utildebug_no_op.dep // 根据 Config.pkgConfig 来依赖所有 pkg for (def entrySet : ConfigUtils.getApplyPkgs().entrySet()) { api entrySet.value.dep } - if (Config.depConfig.feature_mock.isApply) { - api Config.depConfig.feature_mock.dep + if (Config.modules.feature_mock.isApply) { + api ModuleConfig.modules.feature_mock.dep } } def getSuffix() { if (project.name == "feature_launcher_app") return "" - return "." + project.name.substring("feature_".length(), project.name.length() - "_app".length()) + return "." + project. + name. + substring("feature_".length(), project.name.length() - "_app".length()) } def configSigning() { @@ -113,12 +117,14 @@ def configApkName() { if (variant.buildType.name != "debug") { def artifact = variant.getPackageApplicationProvider().get() artifact.outputDirectory = new File("${rootDir.path}/apk") - artifact.outputScope.apkDatas.forEach { apkData -> - apkData.outputFileName = "util" + suffix + - (variant.flavorName == "" ? "" : ("_" + variant.flavorName)) + - "_" + variant.versionName.replace(".", "_") + - "_" + variant.buildType.name + - ".apk" + variant.outputs.each { + it.outputFileName = "util" + suffix + + (variant.flavorName == "" ? "" : ("_" + variant.flavorName)) + + "_" + + variant.versionName.replace(".", "_") + + "_" + + variant.buildType.name + + ".apk" } } } diff --git a/buildCommon.gradle b/buildCommon.gradle new file mode 100644 index 0000000000..2cba3ffea2 --- /dev/null +++ b/buildCommon.gradle @@ -0,0 +1,30 @@ +apply { + plugin "kotlin-android" + plugin "kotlin-android-extensions" +} + +android { + compileSdkVersion Config.compileSdkVersion + defaultConfig { + minSdkVersion Config.minSdkVersion + versionCode Config.versionCode + versionName Config.versionName + consumerProguardFiles 'proguard-rules.pro' + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } +} \ No newline at end of file diff --git a/buildLib.gradle b/buildLib.gradle index e2ad034683..aed207cbee 100644 --- a/buildLib.gradle +++ b/buildLib.gradle @@ -1,34 +1,5 @@ -apply { - plugin "com.android.library" - plugin "kotlin-android" - plugin "kotlin-android-extensions" -} - -android { - compileSdkVersion Config.compileSdkVersion - defaultConfig { - minSdkVersion Config.minSdkVersion - versionCode Config.versionCode - versionName Config.versionName - consumerProguardFiles 'proguard-rules.pro' - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - consumerProguardFiles 'proguard-rules.pro' - } - } - - lintOptions { - abortOnError false - } - -// viewBinding { -// enabled = true -// } -} +apply plugin: "com.android.library" +apply from: "${rootDir.path}/buildCommon.gradle" dependencies { if (project.name.endsWith("_pkg") || project.name.endsWith("_mock")) { @@ -37,6 +8,6 @@ dependencies { api entrySet.value.dep } } else if (project.name.endsWith("_export")) { - api Config.depConfig.lib_common.dep + api Config.modules.lib_common.dep } } \ No newline at end of file diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 0000000000..8a313c3b99 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,8 @@ +//dependencyResolutionManagement { +// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) +// repositories { +// google() +// mavenCentral() +// jcenter() // Warning: this repository is going to shut down soon +// } +//} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index 9a6e8d1b2a..9a8d69d659 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -1,11 +1,3 @@ -/** - *
- * author: blankj - * blog : http://blankj.com - * time : 2019/07/13 - * desc : - *- */ class Config { static applicationId = 'com.blankj.androidutilcode' @@ -14,75 +6,84 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_028_002 - static versionName = '1.28.3'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_031_001 + static versionName = '1.31.1'// E.g. 1.9.72 => 1,009,072 // lib version - static gradlePluginVersion = '3.5.0' - static kotlinVersion = '1.3.50' - static supportVersion = '28.0.0' + static gradlePluginVersion = '4.1.0' + static kotlinVersion = '1.3.72' + static androidxVersion = '1.0.0' - static depConfig = [ - /*Never delete this line*/ - /*Generated by "config.json"*/ - plugin_api_gradle_plugin : new DepConfig(true , true , ":plugin:api-gradle-plugin"), - plugin_bus_gradle_plugin : new DepConfig(true , true , ":plugin:bus-gradle-plugin"), - feature_mock : new DepConfig(false, true , ":feature:mock"), - feature_launcher_app : new DepConfig(true , true , ":feature:launcher:app"), - feature_main_app : new DepConfig(false, true , ":feature:main:app"), - feature_main_pkg : new DepConfig(true , true , ":feature:main:pkg"), - feature_subutil_app : new DepConfig(false, true , ":feature:subutil:app"), - feature_subutil_pkg : new DepConfig(true , true , ":feature:subutil:pkg"), - feature_subutil_export : new DepConfig(true , true , ":feature:subutil:export"), - feature_utilcode_app : new DepConfig(false, true , ":feature:utilcode:app"), - feature_utilcode_pkg : new DepConfig(true , true , ":feature:utilcode:pkg"), - feature_utilcode_export : new DepConfig(true , true , ":feature:utilcode:export"), - lib_base : new DepConfig(true , true , ":lib:base"), - lib_common : new DepConfig(true , true , ":lib:common"), - lib_subutil : new DepConfig(true , true , ":lib:subutil"), - lib_utilcode : new DepConfig(true , true , ":lib:utilcode", "com.blankj:utilcode:$versionName"), - lib_utildebug : new DepConfig(true , true , ":lib:utildebug"), - lib_utildebug_no_op : new DepConfig(true , true , ":lib:utildebug-no-op"), - /*Never delete this line*/ - plugin_gradle : new DepConfig(pluginPath: "com.android.tools.build:gradle:$gradlePluginVersion"), - plugin_kotlin : new DepConfig(pluginPath: "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"), - plugin_maven : new DepConfig(pluginPath: "com.github.dcendents:android-maven-gradle-plugin:2.1", pluginId: "com.github.dcendents.android-maven"),// 上传到 maven - plugin_bintray : new DepConfig(pluginPath: "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4", pluginId: "com.jfrog.bintray"),// 上传到 bintray - plugin_traute : new DepConfig(pluginPath: "tech.harmonysoft:traute-gradle:1.1.10", pluginId: "tech.harmonysoft.oss.traute"),// 注解转非空判断 + static modules = [ + /*Don't delete this line*/ + /*Generated by "module_config.json"*/ + plugin_api_gradle_plugin : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/api-gradle-plugin"), + plugin_bus_gradle_plugin : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/bus-gradle-plugin"), + plugin_lib_base_transform : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/lib/base-transform", remotePath: "com.blankj:base-transform:1.0"), + plugin_buildSrc_plugin : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/buildSrc-plugin"), + feature_mock : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/mock"), + feature_launcher_app : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/launcher/app"), + feature_main_app : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/main/app"), + feature_main_pkg : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/main/pkg"), + feature_subutil_app : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/subutil/app"), + feature_subutil_pkg : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/subutil/pkg"), + feature_subutil_export : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/subutil/export"), + feature_utilcode_app : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/utilcode/app"), + feature_utilcode_pkg : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/utilcode/pkg"), + feature_utilcode_export : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/utilcode/export", remotePath: "com.blankj:utilcode-export:1.1"), + lib_base : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/base"), + lib_common : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/common"), + lib_subutil : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/subutil"), + lib_utilcode : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utilcode", remotePath: "com.blankj:utilcodex:$Config.versionName"), + lib_utildebug : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utildebug"), + lib_utildebug_no_op : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utildebug-no-op"), + /*Don't delete this line*/ + ] + + static plugins = [ + plugin_gradle : new PluginConfig(path: "com.android.tools.build:gradle:$gradlePluginVersion"), + plugin_kotlin : new PluginConfig(path: "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"), + // 上传到 maven + plugin_maven : new PluginConfig(path: "com.github.dcendents:android-maven-gradle-plugin:2.1", id: "com.github.dcendents.android-maven"), - // 上传新版本插件更新 pluginPath 中的版本号,并设置 isApply = false + // 上传新版本插件更新 path 中的版本号,并设置 isApply = false // 通过 mavenLocal 上传本地版本,设置 isApply = true 即可应用插件来调试,最后通过 bintrayUpload 来发布插件 - plugin_api : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:api-gradle-plugin:1.2", pluginId: "com.blankj.api"), - //./gradlew plugin:plugin_api-gradle-plugin:mavenLocal // 上传到本地 mavenLocal - //./gradlew plugin:plugin_api-gradle-plugin:bintrayUpload // 上传到 jcenter - plugin_bus : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:bus-gradle-plugin:2.4", pluginId: "com.blankj.bus"), - //./gradlew plugin:plugin_bus-gradle-plugin:mavenLocal // 上传到本地 mavenLocal - //./gradlew plugin:plugin_bus-gradle-plugin:bintrayUpload // 上传到 jcenter + plugin_api : new PluginConfig(isApply: true, useLocal: false, path: "com.blankj:api-gradle-plugin:1.5", id: "com.blankj.api"), + //./gradlew clean :plugin_api-gradle-plugin:mavenLocal // 上传到本地 mavenLocal + //./gradlew clean :plugin_api-gradle-plugin:bintrayUpload // 上传到 jcenter + plugin_bus : new PluginConfig(isApply: true, useLocal: false, path: "com.blankj:bus-gradle-plugin:2.6", id: "com.blankj.bus"), + //./gradlew clean :plugin_bus-gradle-plugin:mavenLocal // 上传到本地 mavenLocal + //./gradlew clean :plugin_bus-gradle-plugin:bintrayUpload // 上传到 jcenter + plugin_buildSrc: new PluginConfig(isApply: false, useLocal: false, path: "com.blankj:buildSrc-plugin:1.0", id: "com.blankj.buildSrc"), + //./gradlew clean :plugin_bus-gradle-plugin:mavenLocal // 上传到本地 mavenLocal + //./gradlew clean :plugin_bus-gradle-plugin:bintrayUpload // 上传到 jcenter + ] - support_appcompat_v7 : new DepConfig("com.android.support:appcompat-v7:$supportVersion"), - support_design : new DepConfig("com.android.support:design:$supportVersion"), - support_multidex : new DepConfig("com.android.support:multidex:1.0.2"), - support_constraint : new DepConfig("com.android.support.constraint:constraint-layout:1.1.3"), + static libs = [ + androidx_appcompat : new LibConfig(path: "androidx.appcompat:appcompat:$androidxVersion"), + androidx_material : new LibConfig(path: "com.google.android.material:material:$androidxVersion"), + androidx_multidex : new LibConfig(path: "androidx.multidex:multidex:2.0.0"), + androidx_constraint: new LibConfig(path: "androidx.constraintlayout:constraintlayout:1.1.3"), - kotlin : new DepConfig("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"), + kotlin : new LibConfig(path: "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"), - leakcanary_android : new DepConfig("com.squareup.leakcanary:leakcanary-android:2.1"), + leakcanary : new LibConfig(path: "com.squareup.leakcanary:leakcanary-android:2.1"), - free_proguard : new DepConfig("com.blankj:free-proguard:1.0.2"), - swipe_panel : new DepConfig("com.blankj:swipe-panel:1.2"), + free_proguard : new LibConfig(path: "com.blankj:free-proguard:1.0.2"), + swipe_panel : new LibConfig(path: "com.blankj:swipe-panel:1.2"), - gson : new DepConfig("com.google.code.gson:gson:2.8.5"), - glide : new DepConfig("com.github.bumptech.glide:glide:4.7.1"), - retrofit : new DepConfig("com.squareup.retrofit2:retrofit:2.4.0"), - commons_io : new DepConfig("commons-io:commons-io:2.6"), + gson : new LibConfig(path: "com.google.code.gson:gson:2.8.5"), + glide : new LibConfig(path: "com.github.bumptech.glide:glide:4.7.1"), + retrofit : new LibConfig(path: "com.squareup.retrofit2:retrofit:2.4.0"), + commons_io : new LibConfig(path: "commons-io:commons-io:2.6"), - eventbus_lib : new DepConfig("org.greenrobot:eventbus:3.1.1"), - eventbus_processor : new DepConfig("org.greenrobot:eventbus-annotation-processor:3.0.1"), + eventbus_lib : new LibConfig(path: "org.greenrobot:eventbus:3.1.1"), + eventbus_processor : new LibConfig(path: "org.greenrobot:eventbus-annotation-processor:3.0.1"), - photo_view : new DepConfig("com.github.chrisbanes:PhotoView:2.0.0"), + photo_view : new LibConfig(path: "com.github.chrisbanes:PhotoView:2.0.0"), - test_junit : new DepConfig("junit:junit:4.12"), - test_robolectric : new DepConfig("org.robolectric:robolectric:4.3.1"), + test_junit : new LibConfig(path: "junit:junit:4.12"), + test_robolectric : new LibConfig(path: "org.robolectric:robolectric:4.3.1"), ] } -//./gradlew clean lib:lib_utilcode:bintrayUpload \ No newline at end of file +//./gradlew clean :lib_utilcode:bintrayUpload \ No newline at end of file diff --git a/buildSrc/src/main/groovy/ConfigUtils.groovy b/buildSrc/src/main/groovy/ConfigUtils.groovy index e5fa63146c..6a09d2f2d9 100644 --- a/buildSrc/src/main/groovy/ConfigUtils.groovy +++ b/buildSrc/src/main/groovy/ConfigUtils.groovy @@ -17,7 +17,6 @@ class ConfigUtils { generateDep(gradle) addCommonGradle(gradle) TaskDurationUtils.init(gradle) - GitUtils.init(gradle) } /** @@ -25,16 +24,12 @@ class ConfigUtils { */ private static void generateDep(Gradle gradle) { def configs = [:] - for (Map.Entry
- * author: blankj - * blog : http://blankj.com - * time : 2019/07/13 - * desc : - *- */ -class DepConfig { - boolean isApply // 是否应用 - boolean useLocal // 是否使用本地的 - String localPath // 本地路径 - String remotePath// 远程路径 - String pluginPath// 插件路径 - String pluginId // 插件 ID - def dep // 根据条件生成项目最终的依赖项 - - DepConfig() { - isApply = true - } - - DepConfig(String path) { - this(true, path) - } - - DepConfig(boolean isApply, String path) { - if (path.startsWith(":")) { - this.useLocal = true - this.localPath = path - this.isApply = isApply - } else { - this.useLocal = false - this.remotePath = path - this.isApply = isApply - } - } - - DepConfig(boolean useLocal, String localPath, String remotePath) { - this(true, useLocal, localPath, remotePath) - } - - DepConfig(boolean isApply, boolean useLocal, String localPath) { - this(isApply, useLocal, localPath, null) - } - - DepConfig(boolean isApply, boolean useLocal, String localPath, String remotePath) { - this.isApply = isApply - this.useLocal = useLocal - this.localPath = localPath - this.remotePath = remotePath - } - - void setPluginPath(String pluginPath) { - this.pluginPath = pluginPath - this.remotePath = pluginPath - } - - String getPath() { - if (pluginPath != null) return pluginPath - return useLocal ? localPath : remotePath - } - - String getGroupId() { - String[] splits = remotePath.split(":") - return splits.length == 3 ? splits[0] : null - } - - String getArtifactId() { - String[] splits = remotePath.split(":") - return splits.length == 3 ? splits[1] : null - } - - String getVersion() { - String[] splits = remotePath.split(":") - return splits.length == 3 ? splits[2] : null - } - - String getProjectPath() { - return localPath.substring(0, localPath.lastIndexOf(":")) + ":" + localPath.substring(1).replace(":", "_") - } - - @Override - String toString() { - return "{ isApply = ${getFlag(isApply)}" + - ", useLocal = ${getFlag(useLocal)}" + - (dep == null ? ", path = " + path : (", dep = " + dep)) + - " }" - } - - static String getFlag(boolean b) { - return b ? "✅" : "❌" - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/GitUtils.groovy b/buildSrc/src/main/groovy/GitUtils.groovy deleted file mode 100644 index f525377a79..0000000000 --- a/buildSrc/src/main/groovy/GitUtils.groovy +++ /dev/null @@ -1,111 +0,0 @@ -import org.gradle.api.Action -import org.gradle.api.Project -import org.gradle.api.invocation.Gradle - -import java.text.SimpleDateFormat - -/** - *
- * author: blankj - * blog : http://blankj.com - * time : 2019/08/16 - * desc : - *- */ -class GitUtils { - - private static Project rootProject; - - static void init(Gradle gradle) { - rootProject = gradle.rootProject - addGitHelpTask() - } - - static def addGitHelpTask() { - rootProject.task("gitHelp").doLast { - def commands = [ - " ############## input command code #################", - " # [1] Git Push #", - " # [2] Git Push And Merge to Master #", - " # [3] Git New Branch #", - " # [0] exit #", - " ###################################################", - ] - String commandTips = String.join(System.getProperty("line.separator"), commands) - while (true) { - GLog.l(commandTips) - Scanner scanner = new Scanner(System.in) - def input = scanner.next() - GLog.l(input) - switch (input) { - case "1": - gitPush() - break - case "2": - gitPushAndMerge2Master() - break - case "3": - gitNewBranch() - break - case "0": - return - } - } - } - } - - static void gitPush() { - String branchName = getGitBranch() - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd") - String date = simpleDateFormat.format(new Date()) - exeCmd( - "git add -A", - "git commit -m \"see $date log\"", - "git push origin $branchName" - ) - } - - static void gitPushAndMerge2Master() { - String branchName = getGitBranch() - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd") - String date = simpleDateFormat.format(new Date()) - exeCmd( - "git add -A", - "git commit -m \"see $date log\"", - "git push origin $branchName", - "git checkout master", - "git merge $branchName", - "git push origin master", - "git checkout $branchName" - ) - } - - static void gitNewBranch() { - exeCmd( - "git checkout master", - "git checkout -b ${Config.versionName}", - "git push origin ${Config.versionName}:${Config.versionName}", - ) - } - - private static def getGitBranch() { - return exeCmd("git symbolic-ref --short -q HEAD") - } - - private static def exeCmd(String... cmds) { - String output = "" - for (def cmd in cmds) { - output = _exeCmd(cmd) - } - return output - } - - private static def _exeCmd(String cmd) { - def output = new StringBuilder() - GLog.l("Execute command: ${cmd}") - def cmdResult = ShellUtils.execCmd(cmd) - GLog.l("$cmdResult") - return cmdResult.successMsg - } -} -// ./gradlew gitHelp diff --git a/buildSrc/src/main/groovy/LibConfig.groovy b/buildSrc/src/main/groovy/LibConfig.groovy new file mode 100644 index 0000000000..6369553ba0 --- /dev/null +++ b/buildSrc/src/main/groovy/LibConfig.groovy @@ -0,0 +1,29 @@ +class LibConfig { + + String path + + String getGroupId() { + String[] splits = path.split(":") + return splits.length == 3 ? splits[0] : null + } + + String getArtifactId() { + String[] splits = path.split(":") + return splits.length == 3 ? splits[1] : null + } + + String getVersion() { + String[] splits = path.split(":") + return splits.length == 3 ? splits[2] : null + } + + @Override + String toString() { + return "LibConfig { path = $path }" + } + + static String getFlag(boolean b) { + return b ? "✅" : "❌" + } +} + diff --git a/buildSrc/src/main/groovy/ModuleConfig.groovy b/buildSrc/src/main/groovy/ModuleConfig.groovy new file mode 100644 index 0000000000..291abd8ffe --- /dev/null +++ b/buildSrc/src/main/groovy/ModuleConfig.groovy @@ -0,0 +1,35 @@ +class ModuleConfig { + + boolean isApply // 是否应用 + boolean useLocal // 是否使用本地的 + String localPath // 本地路径 + String remotePath // 远程路径 + def dep // 根据条件生成项目最终的依赖项 + + String getGroupId() { + String[] splits = remotePath.split(":") + return splits.length == 3 ? splits[0] : null + } + + String getArtifactId() { + String[] splits = remotePath.split(":") + return splits.length == 3 ? splits[1] : null + } + + String getVersion() { + String[] splits = remotePath.split(":") + return splits.length == 3 ? splits[2] : null + } + + @Override + String toString() { + return "ModuleConfig { isApply = ${getFlag(isApply)}" + + ", dep = " + dep + + " }" + } + + static String getFlag(boolean b) { + return b ? "✅" : "❌" + } +} + diff --git a/buildSrc/src/main/groovy/PluginConfig.groovy b/buildSrc/src/main/groovy/PluginConfig.groovy new file mode 100644 index 0000000000..3811c6a0ca --- /dev/null +++ b/buildSrc/src/main/groovy/PluginConfig.groovy @@ -0,0 +1,35 @@ +final class PluginConfig { + + boolean isApply = true // 是否应用 + boolean useLocal // 是否使用本地的 + String path // 插件路径 + String id // 插件 ID + + String getGroupId() { + String[] splits = path.split(":") + return splits.length == 3 ? splits[0] : null + } + + String getArtifactId() { + String[] splits = path.split(":") + return splits.length == 3 ? splits[1] : null + } + + String getVersion() { + String[] splits = path.split(":") + return splits.length == 3 ? splits[2] : null + } + + @Override + String toString() { + return "PluginConfig { isApply = ${getFlag(isApply)}" + + ", useLocal = ${getFlag(useLocal)}" + + ", path = " + path + + ", id = " + id + + " }" + } + + static String getFlag(boolean b) { + return b ? "✅" : "❌" + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/ShellUtils.java b/buildSrc/src/main/groovy/ShellUtils.java deleted file mode 100644 index ef4917c68e..0000000000 --- a/buildSrc/src/main/groovy/ShellUtils.java +++ /dev/null @@ -1,228 +0,0 @@ -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; - -/** - *
- * author: Blankj - * blog : http://blankj.com - * time : 2016/08/07 - * desc : utils about shell - *- */ -public final class ShellUtils { - - private static final String LINE_SEP = System.getProperty("line.separator"); - - private ShellUtils() { - throw new UnsupportedOperationException("u can't instantiate me..."); - } - - /** - * Execute the command. - * - * @param command The command. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final String command) { - return execCmd(new String[]{command}, false, true); - } - - /** - * Execute the command. - * - * @param command The command. - * @param isRooted True to use root, false otherwise. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final String command, final boolean isRooted) { - return execCmd(new String[]{command}, isRooted, true); - } - - /** - * Execute the command. - * - * @param commands The commands. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final List
* author: blankj diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java index 023c3a919b..e16b4f1934 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java @@ -12,23 +12,18 @@ * desc : **/ -public class MvpModel extends BaseModel implements IMvp.Model { +public class MvpModel extends BaseModel implements MvpMvp.Model { private int index; @Override - public void onCreateModel() { + public void onCreate() { index = 0; } - @Override - public void onDestroyModel() { - - } - @Override public void requestUpdateMsg(final Utils.Consumer
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt index 246cb0dc8e..88286c4df5 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt @@ -3,6 +3,8 @@ package com.blankj.utilcode.pkg.feature.screen import android.content.Context import android.content.Intent import android.os.Build +import android.widget.ImageView +import android.widget.TextView import com.blankj.common.activity.CommonActivity import com.blankj.common.item.CommonItem import com.blankj.common.item.CommonItemClick @@ -61,10 +63,8 @@ class ScreenActivity : CommonActivity() { CommonItemSwitch( "isFullScreen", - Utils.Supplier { - ScreenUtils.isFullScreen(this) - }, - Utils.Consumer { + { ScreenUtils.isFullScreen(this) }, + { if (it) { ScreenUtils.setFullScreen(this) BarUtils.setStatusBarVisibility(this, false) @@ -76,10 +76,8 @@ class ScreenActivity : CommonActivity() { ), CommonItemSwitch( "isLandscape", - Utils.Supplier { - ScreenUtils.isLandscape() - }, - Utils.Consumer { + { ScreenUtils.isLandscape() }, + { if (it) { ScreenUtils.setLandscape(this) } else { @@ -88,7 +86,15 @@ class ScreenActivity : CommonActivity() { } ), CommonItemClick(R.string.screen_screenshot) { - DialogHelper.showScreenshotDialog(ScreenUtils.screenShot(this)) + val iv :ImageView = ImageView(this) + iv.setImageResource(R.mipmap.ic_launcher) + + val tv: TextView = TextView(this) + tv.setText("wowowowwowo") + + DialogHelper.showScreenshotDialog(ImageUtils.view2Bitmap(tv)) + +// DialogHelper.showScreenshotDialog(ScreenUtils.screenShot(this)) } ) } diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt index 568caecff2..dcde367a5b 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt @@ -3,10 +3,10 @@ package com.blankj.utilcode.pkg.feature.snackbar import android.content.Context import android.content.Intent import android.graphics.Color -import android.support.annotation.StringRes import android.text.SpannableStringBuilder import android.view.ViewGroup import android.widget.TextView +import androidx.annotation.StringRes import com.blankj.common.activity.CommonActivity import com.blankj.common.item.CommonItem import com.blankj.common.item.CommonItemClick diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt index bf5d46b154..84c9f868bb 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt @@ -5,7 +5,6 @@ import android.content.Context import android.content.Intent import android.graphics.* import android.os.Bundle -import android.support.annotation.ColorInt import android.text.Layout import android.text.SpannableStringBuilder import android.text.TextPaint @@ -14,6 +13,7 @@ import android.text.style.ClickableSpan import android.text.style.UpdateAppearance import android.view.View import android.view.animation.LinearInterpolator +import androidx.annotation.ColorInt import com.blankj.common.activity.CommonActivity import com.blankj.utilcode.pkg.R import com.blankj.utilcode.util.SpanUtils @@ -81,6 +81,7 @@ class SpanActivity : CommonActivity() { SpanUtils.with(spanAboutTv) .appendLine("SpanUtils").setBackgroundColor(Color.LTGRAY).setBold().setForegroundColor(Color.YELLOW).setHorizontalAlign(Layout.Alignment.ALIGN_CENTER) .appendLine("前景色").setForegroundColor(Color.GREEN) +// .appendLine("测试哈哈").setForegroundColor(Color.RED).setBackgroundColor(Color.LTGRAY).setFontSize(10).setLineHeight(280, SpanUtils.ALIGN_BOTTOM) .appendLine("背景色").setBackgroundColor(Color.LTGRAY) .appendLine("行高居中对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_CENTER).setBackgroundColor(Color.LTGRAY) .appendLine("行高底部对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_BOTTOM).setBackgroundColor(Color.GREEN) diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt index 314ba33d59..f0b6876ad4 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt @@ -1,14 +1,11 @@ package com.blankj.utilcode.pkg.feature.toast -import android.os.Handler -import android.os.Looper -import android.support.annotation.StringRes import android.widget.TextView -import android.widget.Toast - +import androidx.annotation.StringRes import com.blankj.utilcode.pkg.R +import com.blankj.utilcode.util.StringUtils import com.blankj.utilcode.util.ToastUtils -import com.blankj.utilcode.util.Utils +import com.blankj.utilcode.util.ViewUtils /** * ``` @@ -20,62 +17,42 @@ import com.blankj.utilcode.util.Utils */ object CustomToast { - private val HANDLER = Handler(Looper.getMainLooper()) - fun showShort(text: CharSequence) { - showReal(text, Toast.LENGTH_SHORT) + show(text, false) } fun showShort(@StringRes resId: Int) { - show(resId, Toast.LENGTH_SHORT) + show(StringUtils.getString(resId), false) } fun showShort(@StringRes resId: Int, vararg args: Any) { - show(resId, Toast.LENGTH_SHORT, *args) + show(StringUtils.getString(resId, args), false) } fun showShort(format: String, vararg args: Any) { - show(format, Toast.LENGTH_SHORT, *args) + show(StringUtils.format(format, args), false) } fun showLong(text: CharSequence) { - showReal(text, Toast.LENGTH_LONG) + show(text, true) } fun showLong(@StringRes resId: Int) { - show(resId, Toast.LENGTH_LONG) + show(StringUtils.getString(resId), true) } fun showLong(@StringRes resId: Int, vararg args: Any) { - show(resId, Toast.LENGTH_LONG, *args) + show(StringUtils.getString(resId, args), true) } fun showLong(format: String, vararg args: Any) { - show(format, Toast.LENGTH_LONG, *args) - } - - private fun show(@StringRes resId: Int, duration: Int) { - show(Utils.getApp().resources.getString(resId), duration) - } - - private fun show(@StringRes resId: Int, duration: Int, vararg args: Any) { - show(String.format(Utils.getApp().resources.getString(resId), *args), duration) - } - - private fun show(format: String, duration: Int, vararg args: Any) { - showReal(String.format(format, *args), duration) + show(StringUtils.format(format, args), true) } - private fun showReal(text: CharSequence, duration: Int) { - HANDLER.post { - val toastView: TextView - if (duration == Toast.LENGTH_SHORT) { - toastView = ToastUtils.showCustomShort(R.layout.toast_custom) as TextView - } else { - toastView = ToastUtils.showCustomLong(R.layout.toast_custom) as TextView - } - toastView.text = text - } + private fun show(text: CharSequence, isLong: Boolean) { + val textView = ViewUtils.layoutId2View(R.layout.toast_custom) as TextView + textView.text = text + ToastUtils.make().setDurationIsLong(isLong).show(textView) } fun cancel() { diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt index b62d9b33f8..f4267ad3a9 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt @@ -3,14 +3,15 @@ package com.blankj.utilcode.pkg.feature.toast import android.content.Context import android.content.Intent import android.graphics.Color -import android.support.v4.content.ContextCompat import android.view.Gravity +import androidx.core.content.ContextCompat import com.blankj.common.activity.CommonActivity import com.blankj.common.item.CommonItem import com.blankj.common.item.CommonItemClick import com.blankj.utilcode.pkg.R import com.blankj.utilcode.pkg.helper.DialogHelper import com.blankj.utilcode.util.CollectionUtils +import com.blankj.utilcode.util.ColorUtils import com.blankj.utilcode.util.SpanUtils import com.blankj.utilcode.util.ToastUtils @@ -38,30 +39,18 @@ class ToastActivity : CommonActivity() { override fun bindItems(): MutableList> { return CollectionUtils.newArrayList( CommonItemClick(R.string.toast_show_short) { - resetToast() Thread(Runnable { ToastUtils.showShort(R.string.toast_short) }).start() }, CommonItemClick(R.string.toast_show_long) { - resetToast() Thread(Runnable { ToastUtils.showLong(R.string.toast_long) }).start() }, - CommonItemClick(R.string.toast_show_green_font) { - resetToast() - ToastUtils.setMsgColor(Color.GREEN) - ToastUtils.showLong(R.string.toast_green_font) - }, - CommonItemClick(R.string.toast_show_bg_color) { - resetToast() - ToastUtils.setBgColor(ContextCompat.getColor(this, R.color.colorAccent)) - ToastUtils.showLong(R.string.toast_bg_color) + CommonItemClick(R.string.toast_show_null) { + ToastUtils.showLong(null) }, - CommonItemClick(R.string.toast_show_bg_resource) { - resetToast() - ToastUtils.setBgResource(R.drawable.toast_round_rect) - ToastUtils.showLong(R.string.toast_custom_bg) + CommonItemClick(R.string.toast_show_empty) { + ToastUtils.showLong("") }, CommonItemClick(R.string.toast_show_span) { - resetToast() ToastUtils.showLong( SpanUtils() .appendImage(R.mipmap.ic_launcher, SpanUtils.ALIGN_CENTER) @@ -70,34 +59,43 @@ class ToastActivity : CommonActivity() { .create() ) }, - CommonItemClick(R.string.toast_show_custom_view) { - resetToast() - Thread(Runnable { CustomToast.showLong(R.string.toast_custom_view) }).start() + CommonItemClick(R.string.toast_show_long_string) { + ToastUtils.showLong(R.string.toast_long_string) + }, + CommonItemClick(R.string.toast_show_green_font) { + ToastUtils.make().setTextColor(Color.GREEN).setDurationIsLong(true).show(R.string.toast_green_font) + }, + CommonItemClick(R.string.toast_show_bg_color) { + ToastUtils.make().setBgColor(ColorUtils.getColor(R.color.colorAccent)).show(R.string.toast_bg_color) + }, + CommonItemClick(R.string.toast_show_bg_resource) { + ToastUtils.make().setBgResource(R.drawable.toast_round_rect).show(R.string.toast_custom_bg) + }, + CommonItemClick(R.string.toast_show_left_icon) { + ToastUtils.make().setLeftIcon(R.mipmap.ic_launcher).show(R.string.toast_show_left_icon) + }, + CommonItemClick(R.string.toast_show_dark_mode) { + ToastUtils.make().setTopIcon(R.mipmap.ic_launcher).setMode(ToastUtils.MODE.DARK).show(R.string.toast_show_dark_mode) }, CommonItemClick(R.string.toast_show_middle) { - resetToast() - ToastUtils.setGravity(Gravity.CENTER, 0, 0) - ToastUtils.showLong(R.string.toast_middle) + ToastUtils.make().setGravity(Gravity.CENTER, 0, 0).show(R.string.toast_middle) + }, + CommonItemClick(R.string.toast_show_top) { + ToastUtils.make().setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 0).show(R.string.toast_top) + }, + CommonItemClick(R.string.toast_show_custom_view) { + Thread(Runnable { CustomToast.showLong(R.string.toast_custom_view) }).start() }, CommonItemClick(R.string.toast_cancel) { ToastUtils.cancel() }, CommonItemClick(R.string.toast_show_toast_dialog) { - resetToast() DialogHelper.showToastDialog() + }, + CommonItemClick(R.string.toast_show_toast_when_start_activity) { + ToastUtils.showLong(R.string.toast_show_toast_when_start_activity) + start(this) } ) } - - override fun onDestroy() { - resetToast() - super.onDestroy() - } - - private fun resetToast() { - ToastUtils.setMsgColor(-0x1000001) - ToastUtils.setBgColor(-0x1000001) - ToastUtils.setBgResource(-1) - ToastUtils.setGravity(-1, -1, -1) - } } diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt index d2cd9bc147..5dc337bc5b 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt @@ -32,11 +32,23 @@ class VibrateActivity : CommonActivity() { override fun bindItems(): MutableList > { return CollectionUtils.newArrayList( - CommonItemClick(R.string.vibrate_1000ms) { VibrateUtils.vibrate(1000) }, + CommonItemClick(R.string.vibrate_1000ms) { + VibrateUtils.vibrate(1000) + }, CommonItemClick(R.string.vibrate_custom) { VibrateUtils.vibrate(longArrayOf(0, 1000, 1000, 2000, 2000, 1000), 1) }, - CommonItemClick(R.string.vibrate_cancel) { VibrateUtils.cancel() } + CommonItemClick(R.string.vibrate_background) { + backHome() + mContentView.postDelayed({ +// VibrateUtils.vibrate(1000) -- can not vibrate in background + VibrateUtils.vibrateCompat(longArrayOf(0, 1000, 1000, 2000, 2000, 1000), 1) +// VibrateUtils.vibrateCompat(1000) + }, 1000) + }, + CommonItemClick(R.string.vibrate_cancel) { + VibrateUtils.cancel() + } ) } @@ -44,4 +56,11 @@ class VibrateActivity : CommonActivity() { super.onDestroy() VibrateUtils.cancel() } + + private fun backHome() { + val intent = Intent(Intent.ACTION_MAIN).apply { + addCategory(Intent.CATEGORY_HOME) + } + startActivity(intent) + } } diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt new file mode 100644 index 0000000000..26d67dda07 --- /dev/null +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt @@ -0,0 +1,63 @@ +package com.blankj.utilcode.pkg.feature.volume + +import android.content.Context +import android.content.Intent +import android.media.AudioManager +import android.widget.SeekBar +import com.blankj.common.activity.CommonActivity +import com.blankj.common.item.CommonItem +import com.blankj.common.item.CommonItemSeekBar +import com.blankj.utilcode.pkg.R +import com.blankj.utilcode.util.CollectionUtils +import com.blankj.utilcode.util.VolumeUtils + +/** + * ``` + * author: Blankj + * blog : http://blankj.com + * time : 2018/12/29 + * desc : demo about VibrateUtils + * ``` + */ +class VolumeActivity : CommonActivity() { + + companion object { + fun start(context: Context) { + val starter = Intent(context, VolumeActivity::class.java) + context.startActivity(starter) + } + } + + override fun bindTitleRes(): Int { + return R.string.demo_volume + } + + override fun bindItems(): MutableList > { + return CollectionUtils.newArrayList( + getItemSeekBar("Voice Call", AudioManager.STREAM_VOICE_CALL), + getItemSeekBar("System", AudioManager.STREAM_SYSTEM), + getItemSeekBar("Music", AudioManager.STREAM_MUSIC), + getItemSeekBar("Ring", AudioManager.STREAM_RING), + getItemSeekBar("Alarm", AudioManager.STREAM_ALARM), + getItemSeekBar("Notification", AudioManager.STREAM_NOTIFICATION), + getItemSeekBar("Dtmf", AudioManager.STREAM_DTMF) + ) + } + + private fun getItemSeekBar(title: CharSequence, streamType: Int): CommonItemSeekBar { + return CommonItemSeekBar(title, VolumeUtils.getMaxVolume(streamType), object : CommonItemSeekBar.ProgressListener() { + override fun getCurValue(): Int { + return VolumeUtils.getVolume(streamType) + } + + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + VolumeUtils.setVolume(streamType, progress, AudioManager.FLAG_SHOW_UI) + } + }) + } + + override fun onResume() { + super.onResume() + itemsView.updateItems(bindItems()) + } +} diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt index 081ae6f071..7d38fda3ca 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt @@ -4,9 +4,7 @@ import android.content.Context import android.content.DialogInterface import android.graphics.Bitmap import android.graphics.drawable.ColorDrawable -import android.support.v4.app.FragmentActivity import android.text.method.ScrollingMovementMethod -import android.util.Pair import android.view.Gravity import android.view.View import android.view.Window @@ -14,11 +12,14 @@ import android.widget.Button import android.widget.EditText import android.widget.ImageView import android.widget.TextView +import androidx.fragment.app.FragmentActivity import com.blankj.base.dialog.BaseDialogFragment import com.blankj.base.dialog.DialogLayoutCallback -import com.blankj.common.dialog.CommonDialogContent import com.blankj.utilcode.pkg.R -import com.blankj.utilcode.util.* +import com.blankj.utilcode.util.ActivityUtils +import com.blankj.utilcode.util.KeyboardUtils +import com.blankj.utilcode.util.ScreenUtils +import com.blankj.utilcode.util.ToastUtils /** * ``` @@ -30,30 +31,6 @@ import com.blankj.utilcode.util.* */ object DialogHelper { - fun showRationaleDialog(context: Context, shouldRequest: PermissionUtils.OnRationaleListener.ShouldRequest) { - CommonDialogContent().init(context, - StringUtils.getString(android.R.string.dialog_alert_title), - StringUtils.getString(R.string.permission_rationale_message), - Pair(StringUtils.getString(android.R.string.ok), View.OnClickListener { - shouldRequest.again(true) - }), - Pair(StringUtils.getString(android.R.string.cancel), View.OnClickListener { - shouldRequest.again(false) - })).show() - } - - fun showOpenAppSettingDialog(context: Context) { - CommonDialogContent().init(context, - StringUtils.getString(android.R.string.dialog_alert_title), - StringUtils.getString(R.string.permission_denied_forever_message), - Pair(StringUtils.getString(android.R.string.ok), View.OnClickListener { - PermissionUtils.launchAppDetailsSettings() - }), - Pair(StringUtils.getString(android.R.string.cancel), View.OnClickListener { - })) - .show() - } - fun showKeyboardDialog(context: Context) { BaseDialogFragment().init(context, object : DialogLayoutCallback { override fun bindTheme(): Int { @@ -86,6 +63,7 @@ object DialogHelper { dialog.dialog.setOnShowListener(DialogInterface.OnShowListener { KeyboardUtils.fixAndroidBug5497(dialog.dialog.window!!) + KeyboardUtils.showSoftInput() }) } @@ -177,4 +155,4 @@ object DialogHelper { override fun onDismiss(dialog: BaseDialogFragment) {} }).show() } -} +} \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/PermissionHelper.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/PermissionHelper.kt deleted file mode 100644 index 3fff3a3e6f..0000000000 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/PermissionHelper.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.blankj.utilcode.pkg.helper - -import android.content.Context -import com.blankj.utilcode.constant.PermissionConstants -import com.blankj.utilcode.util.LogUtils -import com.blankj.utilcode.util.PermissionUtils - -/** - * ``` - * author: Blankj - * blog : http://blankj.com - * time : 2018/01/06 - * desc : helper about permission - * ``` - */ -object PermissionHelper { - - fun requestCamera(context: Context, listener: OnPermissionGrantedListener, - deniedListener: OnPermissionDeniedListener) { - request(context, listener, deniedListener, PermissionConstants.CAMERA) - } - - fun requestStorage(context: Context, listener: OnPermissionGrantedListener, - deniedListener: OnPermissionDeniedListener) { - request(context, listener, deniedListener, PermissionConstants.STORAGE) - } - - fun requestPhone(context: Context, listener: OnPermissionGrantedListener, - deniedListener: OnPermissionDeniedListener) { - request(context, listener, deniedListener, PermissionConstants.PHONE) - } - - private fun request(context: Context, grantedListener: OnPermissionGrantedListener, - deniedListener: OnPermissionDeniedListener, - @PermissionConstants.Permission vararg permissions: String) { - PermissionUtils.permission(*permissions) - .rationale { activity, shouldRequest -> DialogHelper.showRationaleDialog(activity, shouldRequest) } - .callback(object : PermissionUtils.FullCallback { - override fun onGranted(permissionsGranted: List ) { - LogUtils.d(permissionsGranted) - grantedListener.onPermissionGranted() - } - - override fun onDenied(permissionsDeniedForever: List , permissionsDenied: List ) { - LogUtils.d(permissionsDeniedForever, permissionsDenied) - if (!permissionsDeniedForever.isEmpty()) { - DialogHelper.showOpenAppSettingDialog(context) - return - } - deniedListener.onPermissionDenied() - } - }) - .request() - } - - interface OnPermissionGrantedListener { - fun onPermissionGranted() - } - - interface OnPermissionDeniedListener { - fun onPermissionDenied() - } -} diff --git a/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml b/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml index abe259f89f..50a4898a07 100644 --- a/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml +++ b/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml @@ -2,8 +2,9 @@ \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml b/feature/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml new file mode 100644 index 0000000000..278fe8c2c6 --- /dev/null +++ b/feature/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml @@ -0,0 +1,34 @@ + + + android:angle="180" + android:centerColor="@android:color/transparent" + android:endColor="@color/colorPrimary" + android:startColor="@color/colorPrimary" /> + + + + + + + + diff --git a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml index 0214eb4806..2f8476a4a0 100644 --- a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml +++ b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml @@ -7,7 +7,7 @@ android:fillViewport="true" tools:context=".feature.adaptScreen.AdaptCloseActivity"> -@@ -42,6 +42,6 @@ android:textSize="30pt" app:layout_constraintTop_toBottomOf="@id/adaptScreenCloseAdaptDpTv" /> - + \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml index 819d6bb99d..75fa87e8e5 100644 --- a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml +++ b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent" tools:context=".feature.adaptScreen.AdaptHeightActivity"> -@@ -93,6 +93,6 @@ android:textSize="30pt" /> - + \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml index 9c5e953ecb..b6bfdb2c80 100644 --- a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml +++ b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml @@ -7,7 +7,7 @@ android:fillViewport="true" tools:context=".feature.adaptScreen.AdaptWidthActivity"> -@@ -148,6 +148,6 @@ - + \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml index 23dbb69305..16518fc22f 100644 --- a/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml +++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent" android:orientation="vertical"> -- - + + \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml b/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml index 84ac729412..20efc6c063 100644 --- a/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml +++ b/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml @@ -3,11 +3,10 @@ Language Demo -Language -Language App Context -Language Activity Context Apply Simple Chinese Apply American +Apply English +Apply Arabic Apply System \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml b/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml index d1ba24cff1..e06759a6d0 100644 --- a/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml +++ b/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml @@ -3,11 +3,10 @@语言例子 -语言 -App 上下文语言 -Activity 上下文语言 -应用简体中文 -应用英语 -应用系统语言 +设置简体中文 +设置美语 +设置英语 +设置阿拉伯语 +设置系统语言 \ No newline at end of file diff --git a/feature/utilcode/pkg/src/main/res/values/strings.xml b/feature/utilcode/pkg/src/main/res/values/strings.xml index 02f2622ab2..551f9adbaf 100644 --- a/feature/utilcode/pkg/src/main/res/values/strings.xml +++ b/feature/utilcode/pkg/src/main/res/values/strings.xml @@ -9,12 +9,14 @@BusUtils Demo CleanUtils Demo ClickUtils Demo +ClipboardUtils Demo CrashUtils Demo DeviceUtils Demo FileUtils Demo FlashlightUtils Demo FragmentUtils Demo ImageUtils Demo +IntentUtils Demo KeyboardUtils Demo Language Demo LogUtils Demo @@ -40,6 +42,7 @@UiMessage Demo TransActivity Demo VibrateUtils Demo +VolumeUtils Demo Shared Element @@ -138,6 +141,7 @@Clean Internal Databases Clean Internal SP Clean External Cache +cleanAppUserData Click View Scale Default @@ -226,18 +230,20 @@Close Dialog -Language -Language App Context -Language Activity Context +Relaunch App Apply Simple Chinese Apply American +Apply English +Apply Arabic Apply System Log Switch -Console Switch +Console Switch +Console Listener Switch Head Switch File Switch +File Listener Switch Border Switch Single Tag Switch Log With No Tag @@ -324,15 +330,23 @@Show Short Show Long +Show Null +Show Empty Show Green Font Show Bg Color Show Bg Resource Show Span +Show Left Icon +Show Dark Mode +Show Long String +A toast is a view containing a quick little message for the user. The ToastUtils class helps you create and show those. Show Custom View Custom View Show Middle +Show Top Cancel Show Toast Dialog +Show Toast When Start Activity Short Long Green Font @@ -340,6 +354,7 @@Custom Bg Spannable String Middle +Top Add Listener Id @@ -351,5 +366,6 @@Vibrate 1000ms Vibrate Custom +Vibrate Background Cancel diff --git a/gradle.properties b/gradle.properties index 63f495a02a..b9d5f2bcbf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,10 +13,14 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #org.gradle.jvmargs=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 + +android.enableJetifier=true +android.useAndroidX=true + org.gradle.jvmargs=-Xmx8192m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -XX:-UseGCOverheadLimit -Dfile.encoding=UTF-8 org.gradle.daemon=true #org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.caching=true -#-Dorg.gradle.debug=true --no-daemon \ No newline at end of file +#-Dorg.gradle.debug=true --no-daemon diff --git a/gradle/publish.gradle b/gradle/publish.gradle deleted file mode 100644 index 542c0ff516..0000000000 --- a/gradle/publish.gradle +++ /dev/null @@ -1,223 +0,0 @@ -/* - 1. must add the following classpath in root build.gradle - classpath "com.github.dcendents:android-maven-gradle-plugin:2.1" - classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" - - 2. add bintrayUser, bintrayKey in root local.properties - - 3. copy the file to the directory of gradle, and apply the file in the module - apply from: "${rootDir.path}/gradle/publish.gradle" - publish { - name = "UtilCode" - groupId = "com.blankj" - artifactId = "utilcode" - version = "xx.xx" - website = "https://github.com/Blankj/AndroidUtilCode" - } - - 4. execute following command to publish - ./gradlew bintrayUpload -> upload to bintray - ./gradlew mavenLocal -> upload to local maven -*/ - -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -extensions.create('publish', PublishExtension) - -afterEvaluate { - def ext = project['publish'] as PublishExtension - loadBintray(ext) - configMaven(project, ext) - configBintray(project, ext) - configJavadoc(project, ext) -} - -private void loadBintray(PublishExtension ext) { - Properties properties = new Properties() - File localPropertiesFile = project.rootProject.file("local.properties"); - if (localPropertiesFile.exists()) { - properties.load(localPropertiesFile.newDataInputStream()) - ext.bintrayUser = properties.getProperty("bintrayUser") - ext.bintrayKey = properties.getProperty("bintrayKey") - } -} - -def configMaven(Project project, PublishExtension ext) { - project.group = ext.groupId - project.version = ext.version - - project.install { - repositories.mavenInstaller { - configPom(pom, ext) - } - } - - project.tasks.create("mavenLocal", Upload) { - configuration = project.configurations.archives - - repositories.mavenDeployer { - repository(url: uri(new File(project.rootDir.getPath() + "/mavenLocal"))) - configPom(pom, ext) - } - - doFirst { - checkExt(project, ext) - } - } - - project.tasks.findByName("bintrayUpload").doFirst { - checkExt(project, ext) - } -} - -def configPom(pom, PublishExtension ext) { - pom.project { - name ext.name - groupId ext.groupId - artifactId ext.artifactId - version ext.version - packaging isAndroid() ? "aar" : "jar" - description ext.name - url ext.website - - scm { - url ext.website - connection ext.website - developerConnection ext.website + ".git" - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - - developers { - developer { - id ext.bintrayUser - name ext.bintrayUser - } - } - } -} - -static def checkExt(Project project, PublishExtension ext) { - if (ext.isBintrayEmpty()) { - throw new NullPointerException("U should set bintrayUser and bintrayKey in local.properties") - } - ext.check() -} - -def configBintray(Project project, PublishExtension ext) { - project.bintray { - user = ext.bintrayUser - key = ext.bintrayKey - configurations = ['archives'] - override = false - publish = true - pkg { - repo = "maven" - name = ext.name - websiteUrl = ext.website - vcsUrl = ext.website + '.git' - licenses = ["Apache-2.0"] - } - } -} - -private void configJavadoc(Project project, PublishExtension ext) { - if (isAndroid()) { - // This generates sources.jar - task sourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.source - } - - task javadoc(type: Javadoc) { - source = android.sourceSets.main.java.source - classpath += configurations.compile - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - } - - task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir - } - } else { - task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource - } - - task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir - } - } - - if (project.hasProperty("kotlin")) { - // Disable creating javadocs - project.tasks.withType(Javadoc) { - enabled = false - } - } - - javadoc { - options { - encoding "UTF-8" - charSet 'UTF-8' - author true - version ext.version - links "http://docs.oracle.com/javase/7/docs/api" - title "${ext.name} ${ext.version}" - } - } - - artifacts { - archives javadocJar - archives sourcesJar - } -} - -def isAndroid() { - return project.getPlugins().hasPlugin('com.android.application') || - project.getPlugins().hasPlugin('com.android.library') -} - -class PublishExtension { - String name - String groupId - String artifactId - String version - String website - - String bintrayUser - String bintrayKey - - void check() { - checkField(name, "name") - checkField(groupId, "groupId") - checkField(artifactId, "artifactId") - checkField(version, "version") - checkField(website, "website") - - checkField(bintrayUser, "bintrayUser") - checkField(bintrayKey, "bintrayKey") - } - - boolean isBintrayEmpty() { - return isEmpty(bintrayUser) || isEmpty(bintrayKey) - } - - static void checkField(String field, String fieldName) { - if (isEmpty(field)) { - throw new NullPointerException("$fieldName is empty!!") - } - } - - static boolean isEmpty(String str) { - return str == null || str.length() == 0 - } -} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372aef5e..5c2d1cf016 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e4718dff4d..1e0ae1a108 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/gradlew b/gradlew index 9d82f78915..b0d6d0ab5d 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,20 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## ## @@ -6,20 +22,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +64,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +75,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +105,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +170,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282aa6..15e1ee37a7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,100 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lib/base/build.gradle b/lib/base/build.gradle index 20033bc3f0..b7eb9d588c 100644 --- a/lib/base/build.gradle +++ b/lib/base/build.gradle @@ -1,15 +1,14 @@ dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - api Config.depConfig.lib_subutil.dep - api Config.depConfig.lib_utilcode.dep + api Config.modules.lib_subutil.dep + api Config.modules.lib_utilcode.dep - api Config.depConfig.support_appcompat_v7.dep - api Config.depConfig.support_design.dep - api Config.depConfig.support_multidex.dep - api Config.depConfig.support_constraint.dep - api Config.depConfig.kotlin.dep - api Config.depConfig.free_proguard.dep - api Config.depConfig.swipe_panel.dep - api Config.depConfig.eventbus_lib.dep - compileOnly Config.depConfig.lib_utildebug_no_op.dep + api Config.libs.androidx_appcompat.path + api Config.libs.androidx_material.path + api Config.libs.androidx_multidex.path + api Config.libs.androidx_constraint.path + api Config.libs.kotlin.path + api Config.libs.free_proguard.path + api Config.libs.swipe_panel.path + api Config.libs.eventbus_lib.path + compileOnly Config.modules.lib_utildebug_no_op.dep } \ No newline at end of file diff --git a/lib/base/src/main/java/com/blankj/base/BaseActivity.java b/lib/base/src/main/java/com/blankj/base/BaseActivity.java index c0c1fce1ce..c0348203f8 100644 --- a/lib/base/src/main/java/com/blankj/base/BaseActivity.java +++ b/lib/base/src/main/java/com/blankj/base/BaseActivity.java @@ -2,10 +2,12 @@ import android.app.Activity; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; +import androidx.annotation.LayoutRes; +import androidx.appcompat.app.AppCompatActivity; + import com.blankj.utilcode.util.ClickUtils; /** diff --git a/lib/base/src/main/java/com/blankj/base/BaseApplication.java b/lib/base/src/main/java/com/blankj/base/BaseApplication.java index aedea57cb4..f1fd6186c0 100644 --- a/lib/base/src/main/java/com/blankj/base/BaseApplication.java +++ b/lib/base/src/main/java/com/blankj/base/BaseApplication.java @@ -2,7 +2,8 @@ import android.app.Application; import android.content.Context; -import android.support.multidex.MultiDex; + +import androidx.multidex.MultiDex; import com.blankj.utilcode.util.AppUtils; import com.blankj.utilcode.util.CrashUtils; @@ -74,15 +75,16 @@ public String format(ArrayList arrayList) { return "LogUtils Formatter ArrayList { " + arrayList.toString() + " }"; } }) - .setFileWriter(null); + .addFileExtraHead("ExtraKey", "ExtraValue"); LogUtils.i(config.toString()); } private void initCrash() { CrashUtils.init(new CrashUtils.OnCrashListener() { @Override - public void onCrash(String crashInfo, Throwable e) { - LogUtils.e(crashInfo); + public void onCrash(CrashUtils.CrashInfo crashInfo) { + crashInfo.addExtraHead("extraKey", "extraValue"); + LogUtils.e(crashInfo.toString()); AppUtils.relaunchApp(); } }); diff --git a/lib/base/src/main/java/com/blankj/base/BaseFragment.java b/lib/base/src/main/java/com/blankj/base/BaseFragment.java index 2ff0a90913..ab2b8877fe 100644 --- a/lib/base/src/main/java/com/blankj/base/BaseFragment.java +++ b/lib/base/src/main/java/com/blankj/base/BaseFragment.java @@ -2,13 +2,6 @@ import android.content.Context; import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -17,6 +10,14 @@ import com.blankj.utilcode.util.AppUtils; import com.blankj.utilcode.util.ClickUtils; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + /** ** author: Blankj @@ -89,7 +90,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { } else { ft.show(this); } - ft.commitAllowingStateLoss(); + ft.commitNowAllowingStateLoss(); } Bundle bundle = getArguments(); initData(bundle); diff --git a/lib/base/src/main/java/com/blankj/base/IBaseView.java b/lib/base/src/main/java/com/blankj/base/IBaseView.java index 282649b774..821cbf4399 100644 --- a/lib/base/src/main/java/com/blankj/base/IBaseView.java +++ b/lib/base/src/main/java/com/blankj/base/IBaseView.java @@ -1,11 +1,12 @@ package com.blankj.base; import android.os.Bundle; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** *diff --git a/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java index 274f451a56..1599d8becc 100644 --- a/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java +++ b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java @@ -4,13 +4,14 @@ import android.app.Dialog; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; import android.view.View; import android.view.Window; import com.blankj.utilcode.util.ActivityUtils; import com.blankj.utilcode.util.ThreadUtils; +import androidx.annotation.NonNull; + /** ** author: blankj diff --git a/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java index d83dc5cc32..e115e78878 100644 --- a/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java +++ b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java @@ -6,12 +6,6 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -21,6 +15,13 @@ import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.ThreadUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + /** ** author: blankj diff --git a/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java b/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java index 7d1c6e632a..defd34483f 100644 --- a/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java +++ b/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java @@ -2,9 +2,10 @@ import android.app.Activity; import android.app.Dialog; -import android.support.annotation.NonNull; import android.view.Window; +import androidx.annotation.NonNull; + /** ** author: blankj diff --git a/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java b/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java index cbdd94c2be..b48ed32f23 100644 --- a/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java +++ b/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java @@ -1,10 +1,8 @@ package com.blankj.base.mvp; -import com.blankj.utilcode.util.ThreadUtils; -import com.blankj.utilcode.util.ToastUtils; +import android.util.Log; -import java.util.ArrayList; -import java.util.List; +import androidx.annotation.CallSuper; /** *@@ -16,24 +14,12 @@ */ public abstract class BaseModel { - private ListmTasks = new ArrayList<>(); + private static final String TAG = BaseView.TAG; - public abstract void onCreateModel(); + public abstract void onCreate(); - public abstract void onDestroyModel(); - - public ThreadUtils.Task addAutoDestroyTask(ThreadUtils.Task task) { - if (task == null) return null; - mTasks.add(task); - return task; - } - - void destroy() { - onDestroyModel(); - for (ThreadUtils.Task task : mTasks) { - if (task == null) continue; - task.cancel(); - ToastUtils.showLong("Mvp Task Canceled."); - } + @CallSuper + public void onDestroy() { + Log.i(TAG, "destroy model: " + getClass().getSimpleName()); } } diff --git a/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java b/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java index 7365c3490a..32e672417b 100644 --- a/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java +++ b/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java @@ -1,16 +1,14 @@ package com.blankj.base.mvp; -import android.app.Activity; -import android.arch.lifecycle.Lifecycle; -import android.support.annotation.NonNull; - -import com.blankj.utilcode.util.ActivityUtils; -import com.blankj.utilcode.util.LogUtils; -import com.blankj.utilcode.util.Utils; +import android.util.Log; import java.util.HashMap; import java.util.Map; +import androidx.annotation.CallSuper; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + /** * * author: blankj @@ -19,17 +17,19 @@ * desc : **/ -public abstract class BasePresenterextends Utils.ActivityLifecycleCallbacks { +public abstract class BasePresenter { + + private static final String TAG = BaseView.TAG; - private V mView; - private Map mModelMap = new HashMap<>(); + private V mView; + private Map , BaseModel> mModelMap = new HashMap<>(); + private boolean isAlive = true; - public abstract void onAttachView(); + public abstract void onBindView(); void bindView(V view) { this.mView = view; - onAttachView(); - ActivityUtils.addActivityLifecycleCallbacks(mView.getActivity(), this); + onBindView(); } public V getView() { @@ -45,35 +45,29 @@ public M getModel(Class modelClass) { try { M model = modelClass.newInstance(); mModelMap.put(modelClass, model); - model.onCreateModel(); + model.onCreate(); return model; } catch (IllegalAccessException e) { - e.printStackTrace(); + Log.e("BasePresenter", "getModel", e); } catch (InstantiationException e) { - e.printStackTrace(); + Log.e("BasePresenter", "getModel", e); } return null; } - @Override - public void onLifecycleChanged(@NonNull Activity activity, Lifecycle.Event event) { - super.onLifecycleChanged(activity, event); - if (event == Lifecycle.Event.ON_DESTROY) { - destroyPresenter(); - } - LogUtils.i("onLifecycleChanged: " + event); - } - - private void destroyPresenter() { - if (mView != null) { - mView.mPresenterMap.remove(this.getClass()); - mView.onDestroyView(); - } + @CallSuper + public void onDestroy() { + Log.i(TAG, "destroy presenter: " + getClass().getSimpleName()); + isAlive = false; for (BaseModel model : mModelMap.values()) { if (model != null) { - model.destroy(); + model.onDestroy(); } } mModelMap.clear(); } + + public boolean isAlive() { + return isAlive; + } } diff --git a/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java b/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java index a870e06d82..a68909d01f 100644 --- a/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java +++ b/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java @@ -1,17 +1,17 @@ package com.blankj.base.mvp; -import android.app.Activity; -import android.arch.lifecycle.Lifecycle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; - -import com.blankj.utilcode.util.ActivityUtils; -import com.blankj.utilcode.util.Utils; +import android.util.Log; import java.util.HashMap; import java.util.Map; +import androidx.annotation.CallSuper; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; + /** * * author: blankj @@ -20,45 +20,95 @@ * desc : **/ -public abstract class BaseView{ +public class BaseView implements LifecycleObserver { + + public static final String TAG = "UtilsMVP"; - private FragmentActivity mActivity; - private Fragment mFragment; - Map > mPresenterMap = new HashMap<>(); + private FragmentActivity mActivity; + private Fragment mFragment; + private Lifecycle mLifecycle; + private Map , BasePresenter > mPresenterMap = new HashMap<>(); - public abstract void onDestroyView(); + public BaseView(Fragment fragment) { + mFragment = fragment; + mActivity = fragment.getActivity(); + mLifecycle = mFragment.getLifecycle(); + addLifecycle(this); + } public BaseView(FragmentActivity activity) { mActivity = activity; + mLifecycle = mActivity.getLifecycle(); + addLifecycle(this); } - public BaseView(Fragment fragment) { - mFragment = fragment; - mActivity = fragment.getActivity(); + public BaseView(Lifecycle lifecycle) { + mLifecycle = lifecycle; + addLifecycle(this); } public T getActivity() { + if (mActivity == null) { + return null; + } //noinspection unchecked return (T) mActivity; } public T getFragment() { + if (mFragment == null) { + return null; + } //noinspection unchecked return (T) mFragment; } - public void addPresenter(BasePresenter presenter) { + public V addPresenter(BasePresenter presenter) { + if (presenter == null) return (V) this; mPresenterMap.put(presenter.getClass(), presenter); //noinspection unchecked presenter.bindView((V) this); + return (V) this; } public > P getPresenter(Class
presenterClass) { + if (presenterClass == null) { + throw new IllegalArgumentException("presenterClass is null!"); + } BasePresenter
- *basePresenter = mPresenterMap.get(presenterClass); - if (basePresenter != null) { - //noinspection unchecked - return (P) basePresenter; + if (basePresenter == null) { + throw new IllegalArgumentException("presenter of <" + presenterClass.getSimpleName() + "> is not added!"); + } + //noinspection unchecked + return (P) basePresenter; + } + + @CallSuper + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) + public void onDestroy() { + Log.i(TAG, "destroy view: " + getClass().getSimpleName()); + removeLifecycle(this); + for (BasePresenter presenter : mPresenterMap.values()) { + if (presenter != null) { + presenter.onDestroy(); + } + } + mPresenterMap.clear(); + } + + private void addLifecycle(LifecycleObserver observer) { + if (mLifecycle == null) { + Log.w(TAG, "addLifecycle: mLifecycle is null"); + return; + } + mLifecycle.addObserver(observer); + } + + private void removeLifecycle(LifecycleObserver observer) { + if (mLifecycle == null) { + Log.w(TAG, "removeLifecycle: mLifecycle is null"); + return; } - return null; + mLifecycle.removeObserver(observer); } } diff --git a/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java b/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java index c981fe58fc..b0d6de04fa 100644 --- a/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java +++ b/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java @@ -1,8 +1,5 @@ package com.blankj.base.rv; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.LayoutInflater; @@ -11,6 +8,10 @@ import java.util.List; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + /** * * author: Blankj @@ -23,6 +24,7 @@ public abstract class BaseItem{ private static final SparseIntArray LAYOUT_SPARSE_ARRAY = new SparseIntArray(); private static final SparseArray VIEW_SPARSE_ARRAY = new SparseArray<>(); + public boolean isBindViewHolder = false; static ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { int layoutByType = LAYOUT_SPARSE_ARRAY.get(viewType, -1); @@ -38,7 +40,11 @@ static ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType public abstract void bind(@NonNull final ItemViewHolder holder, final int position); + public void partialUpdate(List china unicom: 130, 131, 132, 145, 155, 156, 166, 171, 175, 176, 185, 186
- *china telecom: 133, 153, 173, 177, 180, 181, 189, 199, 191
+ *china mobile: 134(0-8), 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 165, 172, 178, 182, 183, 184, 187, 188, 195, 197, 198
+ *china unicom: 130, 131, 132, 145, 155, 156, 166, 167, 175, 176, 185, 186, 196
+ *china telecom: 133, 149, 153, 162, 173, 177, 180, 181, 189, 190, 191, 199
+ *china broadcasting: 192
*global star: 1349
- *virtual operator: 170
+ *virtual operator: 170, 171
*/ - public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[57])|(15[0-35-9])|(16[6])|(17[0135-8])|(18[0-9])|(19[189]))\\d{8}$"; + public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[579])|(15[0-35-9])|(16[2567])|(17[0-35-8])|(18[0-9])|(19[0-35-9]))\\d{8}$"; /** * Regex of telephone number. */ diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/TimeConstants.java b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/TimeConstants.java index 9932037bf8..45090576e3 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/TimeConstants.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/TimeConstants.java @@ -1,6 +1,6 @@ package com.blankj.utilcode.constant; -import android.support.annotation.IntDef; +import androidx.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ActivityUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ActivityUtils.java index 2a5cc80f3c..d49ce6ff06 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ActivityUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ActivityUtils.java @@ -10,12 +10,6 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.annotation.AnimRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.app.Fragment; -import android.support.v4.util.Pair; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -25,6 +19,13 @@ import java.util.ArrayList; import java.util.List; +import androidx.annotation.AnimRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityOptionsCompat; +import androidx.core.util.Pair; +import androidx.fragment.app.Fragment; + /** ** author: Blankj @@ -39,23 +40,41 @@ private ActivityUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } + /** + * Add callbacks of activity lifecycle. + * + * @param callbacks The callbacks. + */ + public static void addActivityLifecycleCallbacks(@Nullable final Utils.ActivityLifecycleCallbacks callbacks) { + UtilsBridge.addActivityLifecycleCallbacks(callbacks); + } + /** * Add callbacks of activity lifecycle. * * @param activity The activity. * @param callbacks The callbacks. */ - public static void addActivityLifecycleCallbacks(final Activity activity, - final Utils.ActivityLifecycleCallbacks callbacks) { + public static void addActivityLifecycleCallbacks(@Nullable final Activity activity, + @Nullable final Utils.ActivityLifecycleCallbacks callbacks) { UtilsBridge.addActivityLifecycleCallbacks(activity, callbacks); } + /** + * Remove callbacks of activity lifecycle. + * + * @param callbacks The callbacks. + */ + public static void removeActivityLifecycleCallbacks(@Nullable final Utils.ActivityLifecycleCallbacks callbacks) { + UtilsBridge.removeActivityLifecycleCallbacks(callbacks); + } + /** * Remove callbacks of activity lifecycle. * * @param activity The activity. */ - public static void removeActivityLifecycleCallbacks(final Activity activity) { + public static void removeActivityLifecycleCallbacks(@Nullable final Activity activity) { UtilsBridge.removeActivityLifecycleCallbacks(activity); } @@ -65,8 +84,8 @@ public static void removeActivityLifecycleCallbacks(final Activity activity) { * @param activity The activity. * @param callbacks The callbacks. */ - public static void removeActivityLifecycleCallbacks(final Activity activity, - final Utils.ActivityLifecycleCallbacks callbacks) { + public static void removeActivityLifecycleCallbacks(@Nullable final Activity activity, + @Nullable final Utils.ActivityLifecycleCallbacks callbacks) { UtilsBridge.removeActivityLifecycleCallbacks(activity, callbacks); } @@ -76,13 +95,16 @@ public static void removeActivityLifecycleCallbacks(final Activity activity, * @param context The context. * @return the activity by context. */ - public static Activity getActivityByContext(Context context) { + @Nullable + public static Activity getActivityByContext(@Nullable Context context) { + if (context == null) return null; Activity activity = getActivityByContextInner(context); if (!isActivityAlive(activity)) return null; return activity; } - private static Activity getActivityByContextInner(Context context) { + @Nullable + private static Activity getActivityByContextInner(@Nullable Context context) { if (context == null) return null; Listlist = new ArrayList<>(); while (context instanceof ContextWrapper) { @@ -104,7 +126,8 @@ private static Activity getActivityByContextInner(Context context) { return null; } - private static Activity getActivityFromDecorContext(Context context) { + @Nullable + private static Activity getActivityFromDecorContext(@Nullable Context context) { if (context == null) return null; if (context.getClass().getName().equals("com.android.internal.policy.DecorContext")) { try { @@ -141,7 +164,7 @@ public static boolean isActivityExists(@NonNull final String pkg, * @param clz The activity class. */ public static void startActivity(@NonNull final Class extends Activity> clz) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, null, context.getPackageName(), clz.getName(), null); } @@ -153,7 +176,7 @@ public static void startActivity(@NonNull final Class extends Activity> clz) { */ public static void startActivity(@NonNull final Class extends Activity> clz, @Nullable final Bundle options) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, null, context.getPackageName(), clz.getName(), options); } @@ -169,7 +192,7 @@ public static void startActivity(@NonNull final Class extends Activity> clz, public static void startActivity(@NonNull final Class extends Activity> clz, @AnimRes final int enterAnim, @AnimRes final int exitAnim) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, null, context.getPackageName(), clz.getName(), getOptionsBundle(context, enterAnim, exitAnim)); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && context instanceof Activity) { @@ -245,7 +268,7 @@ public static void startActivity(@NonNull final Activity activity, */ public static void startActivity(@NonNull final Bundle extras, @NonNull final Class extends Activity> clz) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, extras, context.getPackageName(), clz.getName(), null); } @@ -259,7 +282,7 @@ public static void startActivity(@NonNull final Bundle extras, public static void startActivity(@NonNull final Bundle extras, @NonNull final Class extends Activity> clz, @Nullable final Bundle options) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, extras, context.getPackageName(), clz.getName(), options); } @@ -277,7 +300,7 @@ public static void startActivity(@NonNull final Bundle extras, @NonNull final Class extends Activity> clz, @AnimRes final int enterAnim, @AnimRes final int exitAnim) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, extras, context.getPackageName(), clz.getName(), getOptionsBundle(context, enterAnim, exitAnim)); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && context instanceof Activity) { @@ -361,7 +384,7 @@ public static void startActivity(@NonNull final Bundle extras, */ public static void startActivity(@NonNull final String pkg, @NonNull final String cls) { - startActivity(UtilsBridge.getTopActivityOrApp(), null, pkg, cls, null); + startActivity(getTopActivityOrApp(), null, pkg, cls, null); } /** @@ -374,7 +397,7 @@ public static void startActivity(@NonNull final String pkg, public static void startActivity(@NonNull final String pkg, @NonNull final String cls, @Nullable final Bundle options) { - startActivity(UtilsBridge.getTopActivityOrApp(), null, pkg, cls, options); + startActivity(getTopActivityOrApp(), null, pkg, cls, options); } /** @@ -391,7 +414,7 @@ public static void startActivity(@NonNull final String pkg, @NonNull final String cls, @AnimRes final int enterAnim, @AnimRes final int exitAnim) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, null, pkg, cls, getOptionsBundle(context, enterAnim, exitAnim)); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && context instanceof Activity) { ((Activity) context).overridePendingTransition(enterAnim, exitAnim); @@ -474,7 +497,7 @@ public static void startActivity(@NonNull final Activity activity, public static void startActivity(@NonNull final Bundle extras, @NonNull final String pkg, @NonNull final String cls) { - startActivity(UtilsBridge.getTopActivityOrApp(), extras, pkg, cls, null); + startActivity(getTopActivityOrApp(), extras, pkg, cls, null); } /** @@ -489,7 +512,7 @@ public static void startActivity(@NonNull final Bundle extras, @NonNull final String pkg, @NonNull final String cls, @Nullable final Bundle options) { - startActivity(UtilsBridge.getTopActivityOrApp(), extras, pkg, cls, options); + startActivity(getTopActivityOrApp(), extras, pkg, cls, options); } /** @@ -508,7 +531,7 @@ public static void startActivity(@NonNull final Bundle extras, @NonNull final String cls, @AnimRes final int enterAnim, @AnimRes final int exitAnim) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, extras, pkg, cls, getOptionsBundle(context, enterAnim, exitAnim)); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && context instanceof Activity) { ((Activity) context).overridePendingTransition(enterAnim, exitAnim); @@ -595,7 +618,7 @@ public static void startActivity(@NonNull final Bundle extras, * @return {@code true}: success
{@code false}: fail */ public static boolean startActivity(@NonNull final Intent intent) { - return startActivity(intent, UtilsBridge.getTopActivityOrApp(), null); + return startActivity(intent, getTopActivityOrApp(), null); } /** @@ -607,7 +630,7 @@ public static boolean startActivity(@NonNull final Intent intent) { */ public static boolean startActivity(@NonNull final Intent intent, @Nullable final Bundle options) { - return startActivity(intent, UtilsBridge.getTopActivityOrApp(), options); + return startActivity(intent, getTopActivityOrApp(), options); } /** @@ -623,7 +646,7 @@ public static boolean startActivity(@NonNull final Intent intent, public static boolean startActivity(@NonNull final Intent intent, @AnimRes final int enterAnim, @AnimRes final int exitAnim) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); boolean isSuccess = startActivity(intent, context, getOptionsBundle(context, enterAnim, exitAnim)); if (isSuccess) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && context instanceof Activity) { @@ -1315,7 +1338,7 @@ public static void startActivityForResult(@NonNull final Fragment fragment, * @param intents The descriptions of the activities to start. */ public static void startActivities(@NonNull final Intent[] intents) { - startActivities(intents, UtilsBridge.getTopActivityOrApp(), null); + startActivities(intents, getTopActivityOrApp(), null); } /** @@ -1326,7 +1349,7 @@ public static void startActivities(@NonNull final Intent[] intents) { */ public static void startActivities(@NonNull final Intent[] intents, @Nullable final Bundle options) { - startActivities(intents, UtilsBridge.getTopActivityOrApp(), options); + startActivities(intents, getTopActivityOrApp(), options); } /** @@ -1341,7 +1364,7 @@ public static void startActivities(@NonNull final Intent[] intents, public static void startActivities(@NonNull final Intent[] intents, @AnimRes final int enterAnim, @AnimRes final int exitAnim) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivities(intents, context, getOptionsBundle(context, enterAnim, exitAnim)); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && context instanceof Activity) { ((Activity) context).overridePendingTransition(enterAnim, exitAnim); @@ -1888,6 +1911,7 @@ public static void finishAllActivitiesExceptNewest(@AnimRes final int enterAnim, * @param activity The activity. * @return the icon of activity */ + @Nullable public static Drawable getActivityIcon(@NonNull final Activity activity) { return getActivityIcon(activity.getComponentName()); } @@ -1898,6 +1922,7 @@ public static Drawable getActivityIcon(@NonNull final Activity activity) { * @param clz The activity class. * @return the icon of activity */ + @Nullable public static Drawable getActivityIcon(@NonNull final Class extends Activity> clz) { return getActivityIcon(new ComponentName(Utils.getApp(), clz)); } @@ -1908,6 +1933,7 @@ public static Drawable getActivityIcon(@NonNull final Class extends Activity> * @param activityName The name of activity. * @return the icon of activity */ + @Nullable public static Drawable getActivityIcon(@NonNull final ComponentName activityName) { PackageManager pm = Utils.getApp().getPackageManager(); try { @@ -1924,6 +1950,7 @@ public static Drawable getActivityIcon(@NonNull final ComponentName activityName * @param activity The activity. * @return the logo of activity */ + @Nullable public static Drawable getActivityLogo(@NonNull final Activity activity) { return getActivityLogo(activity.getComponentName()); } @@ -1934,6 +1961,7 @@ public static Drawable getActivityLogo(@NonNull final Activity activity) { * @param clz The activity class. * @return the logo of activity */ + @Nullable public static Drawable getActivityLogo(@NonNull final Class extends Activity> clz) { return getActivityLogo(new ComponentName(Utils.getApp(), clz)); } @@ -1944,6 +1972,7 @@ public static Drawable getActivityLogo(@NonNull final Class extends Activity> * @param activityName The name of activity. * @return the logo of activity */ + @Nullable public static Drawable getActivityLogo(@NonNull final ComponentName activityName) { PackageManager pm = Utils.getApp().getPackageManager(); try { @@ -1968,28 +1997,22 @@ private static void startActivity(final Context context, private static boolean startActivity(final Intent intent, final Context context, final Bundle options) { - if (!isIntentAvailable(intent)) { - Log.e("ActivityUtils", "intent is unavailable"); - return false; - } if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } - if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - context.startActivity(intent, options); - } else { - context.startActivity(intent); + try { + if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + context.startActivity(intent, options); + } else { + context.startActivity(intent); + } + } catch (Exception e) { + Log.e("ActivityUtils", "An exception occurred in startActivity, error message: " + e.getLocalizedMessage()); + return false; } return true; } - private static boolean isIntentAvailable(final Intent intent) { - return Utils.getApp() - .getPackageManager() - .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) - .size() > 0; - } - private static boolean startActivityForResult(final Activity activity, final Bundle extras, final String pkg, @@ -2006,15 +2029,16 @@ private static boolean startActivityForResult(final Intent intent, final Activity activity, final int requestCode, @Nullable final Bundle options) { - if (!isIntentAvailable(intent)) { - Log.e("ActivityUtils", "intent is unavailable"); + try { + if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + activity.startActivityForResult(intent, requestCode, options); + } else { + activity.startActivityForResult(intent, requestCode); + } + } catch (Exception e) { + Log.e("ActivityUtils", "An exception occurred in startActivityForResult, error message: " + e.getLocalizedMessage()); return false; } - if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - activity.startActivityForResult(intent, requestCode, options); - } else { - activity.startActivityForResult(intent, requestCode); - } return true; } @@ -2049,18 +2073,19 @@ private static boolean startActivityForResult(final Intent intent, final Fragment fragment, final int requestCode, @Nullable final Bundle options) { - if (!isIntentAvailable(intent)) { - Log.e("ActivityUtils", "intent is unavailable"); - return false; - } if (fragment.getActivity() == null) { Log.e("ActivityUtils", "Fragment " + fragment + " not attached to Activity"); return false; } - if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - fragment.startActivityForResult(intent, requestCode, options); - } else { - fragment.startActivityForResult(intent, requestCode); + try { + if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + fragment.startActivityForResult(intent, requestCode, options); + } else { + fragment.startActivityForResult(intent, requestCode); + } + } catch (Exception e) { + Log.e("ActivityUtils", "An exception occurred in fragment.startActivityForResult, error message: " + e.getLocalizedMessage()); + return false; } return true; } @@ -2099,4 +2124,13 @@ private static Bundle getOptionsBundle(final Activity activity, } return ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs).toBundle(); } + + private static Context getTopActivityOrApp() { + if (UtilsBridge.isAppForeground()) { + Activity topActivity = getTopActivity(); + return topActivity == null ? Utils.getApp() : topActivity; + } else { + return Utils.getApp(); + } + } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/AdaptScreenUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/AdaptScreenUtils.java index 5a47ecc9d8..aef62a44dc 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/AdaptScreenUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/AdaptScreenUtils.java @@ -2,12 +2,13 @@ import android.content.res.Resources; import android.util.DisplayMetrics; -import android.util.Log; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import androidx.annotation.NonNull; + /** ** author: Blankj @@ -27,7 +28,8 @@ private AdaptScreenUtils() { /** * Adapt for the horizontal screen, and call it in {@link android.app.Activity#getResources()}. */ - public static Resources adaptWidth(final Resources resources, final int designWidth) { + @NonNull + public static Resources adaptWidth(@NonNull final Resources resources, final int designWidth) { float newXdpi = (resources.getDisplayMetrics().widthPixels * 72f) / designWidth; applyDisplayMetrics(resources, newXdpi); return resources; @@ -36,14 +38,16 @@ public static Resources adaptWidth(final Resources resources, final int designWi /** * Adapt for the vertical screen, and call it in {@link android.app.Activity#getResources()}. */ - public static Resources adaptHeight(final Resources resources, final int designHeight) { + @NonNull + public static Resources adaptHeight(@NonNull final Resources resources, final int designHeight) { return adaptHeight(resources, designHeight, false); } /** * Adapt for the vertical screen, and call it in {@link android.app.Activity#getResources()}. */ - public static Resources adaptHeight(final Resources resources, final int designHeight, final boolean includeNavBar) { + @NonNull + public static Resources adaptHeight(@NonNull final Resources resources, final int designHeight, final boolean includeNavBar) { float screenHeight = (resources.getDisplayMetrics().heightPixels + (includeNavBar ? getNavBarHeight(resources) : 0)) * 72f; float newXdpi = screenHeight / designHeight; @@ -51,7 +55,7 @@ public static Resources adaptHeight(final Resources resources, final int designH return resources; } - private static int getNavBarHeight(final Resources resources) { + private static int getNavBarHeight(@NonNull final Resources resources) { int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId != 0) { return resources.getDimensionPixelSize(resourceId); @@ -64,7 +68,8 @@ private static int getNavBarHeight(final Resources resources) { * @param resources The resources. * @return the resource */ - public static Resources closeAdapt(final Resources resources) { + @NonNull + public static Resources closeAdapt(@NonNull final Resources resources) { float newXdpi = Resources.getSystem().getDisplayMetrics().density * 72f; applyDisplayMetrics(resources, newXdpi); return resources; @@ -92,7 +97,7 @@ public static int px2Pt(final float pxValue) { return (int) (pxValue * 72 / metrics.xdpi + 0.5); } - private static void applyDisplayMetrics(final Resources resources, final float newXdpi) { + private static void applyDisplayMetrics(@NonNull final Resources resources, final float newXdpi) { resources.getDisplayMetrics().xdpi = newXdpi; Utils.getApp().getResources().getDisplayMetrics().xdpi = newXdpi; applyOtherDisplayMetrics(resources, newXdpi); @@ -145,7 +150,7 @@ private static void applyMetricsFields(final Resources resources, final float ne DisplayMetrics dm = (DisplayMetrics) metricsField.get(resources); if (dm != null) dm.xdpi = newXdpi; } catch (Exception e) { - Log.e("AdaptScreenUtils", "applyMetricsFields: " + e); + e.printStackTrace(); } } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ApiUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ApiUtils.java index f99bc77f19..2fb3a88b74 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ApiUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ApiUtils.java @@ -1,6 +1,5 @@ package com.blankj.utilcode.util; -import android.support.annotation.NonNull; import android.util.Log; import java.lang.annotation.ElementType; @@ -11,6 +10,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** ** author: Blankj @@ -47,14 +49,17 @@ private void registerImpl(Class implClass) { * @paramThe type. * @return the api */ + @Nullable public static T getApi(@NonNull final Class apiClass) { return getInstance().getApiInner(apiClass); } - public static void register(Class extends BaseApi> implClass) { + public static void register(@Nullable Class extends BaseApi> implClass) { + if (implClass == null) return; getInstance().registerImpl(implClass); } + @NonNull public static String toString_() { return getInstance().toString(); } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/AppUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/AppUtils.java index 6e96857509..3a07653fb0 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/AppUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/AppUtils.java @@ -1,6 +1,6 @@ package com.blankj.utilcode.util; -import android.annotation.SuppressLint; +import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -8,12 +8,15 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; +import android.content.pm.SigningInfo; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.provider.Settings; -import android.support.annotation.NonNull; +import android.os.Build; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -69,8 +72,22 @@ public static void installApp(final String filePath) { * @param file The file. */ public static void installApp(final File file) { - if (!UtilsBridge.isFileExists(file)) return; - Utils.getApp().startActivity(UtilsBridge.getInstallAppIntent(file)); + Intent installAppIntent = UtilsBridge.getInstallAppIntent(file); + if (installAppIntent == null) return; + Utils.getApp().startActivity(installAppIntent); + } + + /** + * Install the app. + * Target APIs greater than 25 must hold + * {@code
+ * + * @param uri The uri. + */ + public static void installApp(final Uri uri) { + Intent installAppIntent = UtilsBridge.getInstallAppIntent(uri); + if (installAppIntent == null) return; + Utils.getApp().startActivity(installAppIntent); } /** @@ -108,11 +125,7 @@ public static boolean isAppInstalled(final String pkgName) { */ public static boolean isAppRoot() { ShellUtils.CommandResult result = UtilsBridge.execCmd("echo root", true); - if (result.result == 0) return true; - if (result.errorMsg != null) { - Log.d("AppUtils", "isAppRoot() called" + result.errorMsg); - } - return false; + return result.result == 0; } /** @@ -132,8 +145,14 @@ public static boolean isAppDebug() { */ public static boolean isAppDebug(final String packageName) { if (UtilsBridge.isSpace(packageName)) return false; - ApplicationInfo ai = Utils.getApp().getApplicationInfo(); - return ai != null && (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + try { + PackageManager pm = Utils.getApp().getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + return (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } } /** @@ -156,7 +175,7 @@ public static boolean isAppSystem(final String packageName) { try { PackageManager pm = Utils.getApp().getPackageManager(); ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); - return ai != null && (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + return (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return false; @@ -169,18 +188,7 @@ public static boolean isAppSystem(final String packageName) { * @return {@code true}: yes}
{@code false}: no */ public static boolean isAppForeground() { - ActivityManager am = (ActivityManager) Utils.getApp().getSystemService(Context.ACTIVITY_SERVICE); - if (am == null) return false; - Listinfo = am.getRunningAppProcesses(); - if (info == null || info.size() == 0) return false; - for (ActivityManager.RunningAppProcessInfo aInfo : info) { - if (aInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { - if (aInfo.processName.equals(Utils.getApp().getPackageName())) { - return true; - } - } - } - return false; + return UtilsBridge.isAppForeground(); } /** @@ -203,8 +211,6 @@ public static boolean isAppForeground(@NonNull final String pkgName) { */ public static boolean isAppRunning(final String pkgName) { if (UtilsBridge.isSpace(pkgName)) return false; - ApplicationInfo ai = Utils.getApp().getApplicationInfo(); - int uid = ai.uid; ActivityManager am = (ActivityManager) Utils.getApp().getSystemService(Context.ACTIVITY_SERVICE); if (am != null) { List taskInfo = am.getRunningTasks(Integer.MAX_VALUE); @@ -220,7 +226,7 @@ public static boolean isAppRunning(final String pkgName) { List serviceInfo = am.getRunningServices(Integer.MAX_VALUE); if (serviceInfo != null && serviceInfo.size() > 0) { for (ActivityManager.RunningServiceInfo aInfo : serviceInfo) { - if (uid == aInfo.uid) { + if (pkgName.equals(aInfo.service.getPackageName())) { return true; } } @@ -282,13 +288,37 @@ public static void launchAppDetailsSettings() { /** * Launch the application's details settings. * - * @param packageName The name of the package. + * @param pkgName The name of the package. */ - public static void launchAppDetailsSettings(final String packageName) { - if (UtilsBridge.isSpace(packageName)) return; - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + packageName)); - Utils.getApp().startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + public static void launchAppDetailsSettings(final String pkgName) { + if (UtilsBridge.isSpace(pkgName)) return; + Intent intent = UtilsBridge.getLaunchAppDetailsSettingsIntent(pkgName, true); + if (!UtilsBridge.isIntentAvailable(intent)) return; + Utils.getApp().startActivity(intent); + } + + /** + * Launch the application's details settings. + * + * @param activity The activity. + * @param requestCode The requestCode. + */ + public static void launchAppDetailsSettings(final Activity activity, final int requestCode) { + launchAppDetailsSettings(activity, requestCode, Utils.getApp().getPackageName()); + } + + /** + * Launch the application's details settings. + * + * @param activity The activity. + * @param requestCode The requestCode. + * @param pkgName The name of the package. + */ + public static void launchAppDetailsSettings(final Activity activity, final int requestCode, final String pkgName) { + if (activity == null || UtilsBridge.isSpace(pkgName)) return; + Intent intent = UtilsBridge.getLaunchAppDetailsSettingsIntent(pkgName, false); + if (!UtilsBridge.isIntentAvailable(intent)) return; + activity.startActivityForResult(intent, requestCode); } /** @@ -304,6 +334,7 @@ public static void exitApp() { * * @return the application's icon */ + @Nullable public static Drawable getAppIcon() { return getAppIcon(Utils.getApp().getPackageName()); } @@ -314,6 +345,7 @@ public static Drawable getAppIcon() { * @param packageName The name of the package. * @return the application's icon */ + @Nullable public static Drawable getAppIcon(final String packageName) { if (UtilsBridge.isSpace(packageName)) return null; try { @@ -353,11 +385,44 @@ public static int getAppIconId(final String packageName) { } } + + /** + * Return true if this is the first ever time that the application is installed on the device. + * + * @return true if this is the first ever time that the application is installed on the device. + */ + public static boolean isFirstTimeInstall() { + try { + long firstInstallTime = Utils.getApp().getPackageManager().getPackageInfo(getAppPackageName(), 0).firstInstallTime; + long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(getAppPackageName(), 0).lastUpdateTime; + return firstInstallTime == lastUpdateTime; + } catch (Exception e) { + return false; + } + } + + /** + * Return true if app was previously installed and this one is an update/upgrade to that one, returns false if this is a fresh installation and not an update/upgrade. + * + * @return true if app was previously installed and this one is an update/upgrade to that one, returns false if this is a fresh installation and not an update/upgrade. + */ + public static boolean isAppUpgraded() { + try { + long firstInstallTime = Utils.getApp().getPackageManager().getPackageInfo(getAppPackageName(), 0).firstInstallTime; + long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(getAppPackageName(), 0).lastUpdateTime; + return firstInstallTime != lastUpdateTime; + } catch (Exception e) { + return false; + } + } + + /** * Return the application's package name. * * @return the application's package name */ + @NonNull public static String getAppPackageName() { return Utils.getApp().getPackageName(); } @@ -367,6 +432,7 @@ public static String getAppPackageName() { * * @return the application's name */ + @NonNull public static String getAppName() { return getAppName(Utils.getApp().getPackageName()); } @@ -377,12 +443,13 @@ public static String getAppName() { * @param packageName The name of the package. * @return the application's name */ + @NonNull public static String getAppName(final String packageName) { if (UtilsBridge.isSpace(packageName)) return ""; try { PackageManager pm = Utils.getApp().getPackageManager(); PackageInfo pi = pm.getPackageInfo(packageName, 0); - return pi == null ? null : pi.applicationInfo.loadLabel(pm).toString(); + return pi == null ? "" : pi.applicationInfo.loadLabel(pm).toString(); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return ""; @@ -394,6 +461,7 @@ public static String getAppName(final String packageName) { * * @return the application's path */ + @NonNull public static String getAppPath() { return getAppPath(Utils.getApp().getPackageName()); } @@ -404,12 +472,13 @@ public static String getAppPath() { * @param packageName The name of the package. * @return the application's path */ + @NonNull public static String getAppPath(final String packageName) { if (UtilsBridge.isSpace(packageName)) return ""; try { PackageManager pm = Utils.getApp().getPackageManager(); PackageInfo pi = pm.getPackageInfo(packageName, 0); - return pi == null ? null : pi.applicationInfo.sourceDir; + return pi == null ? "" : pi.applicationInfo.sourceDir; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return ""; @@ -421,6 +490,7 @@ public static String getAppPath(final String packageName) { * * @return the application's version name */ + @NonNull public static String getAppVersionName() { return getAppVersionName(Utils.getApp().getPackageName()); } @@ -431,12 +501,13 @@ public static String getAppVersionName() { * @param packageName The name of the package. * @return the application's version name */ + @NonNull public static String getAppVersionName(final String packageName) { if (UtilsBridge.isSpace(packageName)) return ""; try { PackageManager pm = Utils.getApp().getPackageManager(); PackageInfo pi = pm.getPackageInfo(packageName, 0); - return pi == null ? null : pi.versionName; + return pi == null ? "" : pi.versionName; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return ""; @@ -470,13 +541,73 @@ public static int getAppVersionCode(final String packageName) { } } + /** + * Return the application's minimum sdk version code. + * + * @return the application's minimum sdk version code + */ + public static int getAppMinSdkVersion() { + return getAppMinSdkVersion(Utils.getApp().getPackageName()); + } + + /** + * Return the application's minimum sdk version code. + * + * @param packageName The name of the package. + * @return the application's minimum sdk version code + */ + public static int getAppMinSdkVersion(final String packageName) { + if (UtilsBridge.isSpace(packageName)) return -1; + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.N) return -1; + try { + PackageManager pm = Utils.getApp().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + if (null == pi) return -1; + ApplicationInfo ai = pi.applicationInfo; + return null == ai ? -1 : ai.minSdkVersion; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return -1; + } + } + + /** + * Return the application's target sdk version code. + * + * @return the application's target sdk version code + */ + public static int getAppTargetSdkVersion() { + return getAppTargetSdkVersion(Utils.getApp().getPackageName()); + } + + /** + * Return the application's target sdk version code. + * + * @param packageName The name of the package. + * @return the application's target sdk version code + */ + public static int getAppTargetSdkVersion(final String packageName) { + if (UtilsBridge.isSpace(packageName)) return -1; + try { + PackageManager pm = Utils.getApp().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + if (null == pi) return -1; + ApplicationInfo ai = pi.applicationInfo; + return null == ai ? -1 : ai.targetSdkVersion; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return -1; + } + } + /** * Return the application's signature. * * @return the application's signature */ - public static Signature[] getAppSignature() { - return getAppSignature(Utils.getApp().getPackageName()); + @Nullable + public static Signature[] getAppSignatures() { + return getAppSignatures(Utils.getApp().getPackageName()); } /** @@ -485,26 +616,69 @@ public static Signature[] getAppSignature() { * @param packageName The name of the package. * @return the application's signature */ - public static Signature[] getAppSignature(final String packageName) { + @Nullable + public static Signature[] getAppSignatures(final String packageName) { if (UtilsBridge.isSpace(packageName)) return null; try { PackageManager pm = Utils.getApp().getPackageManager(); - @SuppressLint("PackageManagerGetSignatures") - PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); - return pi == null ? null : pi.signatures; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES); + if (pi == null) return null; + + SigningInfo signingInfo = pi.signingInfo; + if (signingInfo.hasMultipleSigners()) { + return signingInfo.getApkContentsSigners(); + } else { + return signingInfo.getSigningCertificateHistory(); + } + } else { + PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + if (pi == null) return null; + + return pi.signatures; + } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return null; } } + /** + * Return the application's signature. + * + * @param file The file. + * @return the application's signature + */ + @Nullable + public static Signature[] getAppSignatures(final File file) { + if (file == null) return null; + PackageManager pm = Utils.getApp().getPackageManager(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + PackageInfo pi = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNING_CERTIFICATES); + if (pi == null) return null; + + SigningInfo signingInfo = pi.signingInfo; + if (signingInfo.hasMultipleSigners()) { + return signingInfo.getApkContentsSigners(); + } else { + return signingInfo.getSigningCertificateHistory(); + } + } else { + PackageInfo pi = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNATURES); + if (pi == null) return null; + + return pi.signatures; + } + } + /** * Return the application's signature for SHA1 value. * * @return the application's signature for SHA1 value */ - public static String getAppSignatureSHA1() { - return getAppSignatureSHA1(Utils.getApp().getPackageName()); + @NonNull + public static List getAppSignaturesSHA1() { + return getAppSignaturesSHA1(Utils.getApp().getPackageName()); } /** @@ -513,8 +687,9 @@ public static String getAppSignatureSHA1() { * @param packageName The name of the package. * @return the application's signature for SHA1 value */ - public static String getAppSignatureSHA1(final String packageName) { - return getAppSignatureHash(packageName, "SHA1"); + @NonNull + public static List getAppSignaturesSHA1(final String packageName) { + return getAppSignaturesHash(packageName, "SHA1"); } /** @@ -522,8 +697,9 @@ public static String getAppSignatureSHA1(final String packageName) { * * @return the application's signature for SHA256 value */ - public static String getAppSignatureSHA256() { - return getAppSignatureSHA256(Utils.getApp().getPackageName()); + @NonNull + public static List getAppSignaturesSHA256() { + return getAppSignaturesSHA256(Utils.getApp().getPackageName()); } /** @@ -532,8 +708,9 @@ public static String getAppSignatureSHA256() { * @param packageName The name of the package. * @return the application's signature for SHA256 value */ - public static String getAppSignatureSHA256(final String packageName) { - return getAppSignatureHash(packageName, "SHA256"); + @NonNull + public static List getAppSignaturesSHA256(final String packageName) { + return getAppSignaturesHash(packageName, "SHA256"); } /** @@ -541,8 +718,9 @@ public static String getAppSignatureSHA256(final String packageName) { * * @return the application's signature for MD5 value */ - public static String getAppSignatureMD5() { - return getAppSignatureMD5(Utils.getApp().getPackageName()); + @NonNull + public static List getAppSignaturesMD5() { + return getAppSignaturesMD5(Utils.getApp().getPackageName()); } /** @@ -551,11 +729,11 @@ public static String getAppSignatureMD5() { * @param packageName The name of the package. * @return the application's signature for MD5 value */ - public static String getAppSignatureMD5(final String packageName) { - return getAppSignatureHash(packageName, "MD5"); + @NonNull + public static List getAppSignaturesMD5(final String packageName) { + return getAppSignaturesHash(packageName, "MD5"); } - /** * Return the application's user-ID. * @@ -576,16 +754,21 @@ public static int getAppUid(String pkgName) { return Utils.getApp().getPackageManager().getApplicationInfo(pkgName, 0).uid; } catch (Exception e) { e.printStackTrace(); + return -1; } - return -1; } - private static String getAppSignatureHash(final String packageName, final String algorithm) { - if (UtilsBridge.isSpace(packageName)) return ""; - Signature[] signature = getAppSignature(packageName); - if (signature == null || signature.length <= 0) return ""; - return UtilsBridge.bytes2HexString(UtilsBridge.hashTemplate(signature[0].toByteArray(), algorithm)) - .replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0"); + private static List getAppSignaturesHash(final String packageName, final String algorithm) { + ArrayList result = new ArrayList<>(); + if (UtilsBridge.isSpace(packageName)) return result; + Signature[] signatures = getAppSignatures(packageName); + if (signatures == null || signatures.length <= 0) return result; + for (Signature signature : signatures) { + String hash = UtilsBridge.bytes2HexString(UtilsBridge.hashTemplate(signature.toByteArray(), algorithm)) + .replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0"); + result.add(hash); + } + return result; } /** @@ -597,11 +780,14 @@ private static String getAppSignatureHash(final String packageName, final String * path of package *version name *version code + *minimum sdk version code + *target sdk version code *is system * * * @return the application's information */ + @Nullable public static AppInfo getAppInfo() { return getAppInfo(Utils.getApp().getPackageName()); } @@ -615,12 +801,15 @@ public static AppInfo getAppInfo() { *path of package *version name *version code + *minimum sdk version code + *target sdk version code *is system * * * @param packageName The name of the package. * @return the application's information */ + @Nullable public static AppInfo getAppInfo(final String packageName) { try { PackageManager pm = Utils.getApp().getPackageManager(); @@ -637,6 +826,7 @@ public static AppInfo getAppInfo(final String packageName) { * * @return the applications' information */ + @NonNull public static ListgetAppsInfo() { List list = new ArrayList<>(); PackageManager pm = Utils.getApp().getPackageManager(); @@ -655,6 +845,7 @@ public static List getAppsInfo() { * * @return the application's package information */ + @Nullable public static AppUtils.AppInfo getApkInfo(final File apkFile) { if (apkFile == null || !apkFile.isFile() || !apkFile.exists()) return null; return getApkInfo(apkFile.getAbsolutePath()); @@ -665,6 +856,7 @@ public static AppUtils.AppInfo getApkInfo(final File apkFile) { * * @return the application's package information */ + @Nullable public static AppUtils.AppInfo getApkInfo(final String apkFilePath) { if (UtilsBridge.isSpace(apkFilePath)) return null; PackageManager pm = Utils.getApp().getPackageManager(); @@ -677,17 +869,41 @@ public static AppUtils.AppInfo getApkInfo(final String apkFilePath) { return getBean(pm, pi); } + + /** + * Return whether the application was first installed. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isFirstTimeInstalled() { + try { + PackageInfo pi = Utils.getApp().getPackageManager().getPackageInfo(Utils.getApp().getPackageName(), 0); + return pi.firstInstallTime == pi.lastUpdateTime; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return true; + } + } + private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) { if (pi == null) return null; - ApplicationInfo ai = pi.applicationInfo; + String versionName = pi.versionName; + int versionCode = pi.versionCode; String packageName = pi.packageName; + ApplicationInfo ai = pi.applicationInfo; + if (ai == null) { + return new AppInfo(packageName, "", null, "", versionName, versionCode, -1, -1, false); + } String name = ai.loadLabel(pm).toString(); Drawable icon = ai.loadIcon(pm); String packagePath = ai.sourceDir; - String versionName = pi.versionName; - int versionCode = pi.versionCode; + int minSdkVersion = -1; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + minSdkVersion = ai.minSdkVersion; + } + int targetSdkVersion = ai.targetSdkVersion; boolean isSystem = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != 0; - return new AppInfo(packageName, name, icon, packagePath, versionName, versionCode, isSystem); + return new AppInfo(packageName, name, icon, packagePath, versionName, versionCode, minSdkVersion, targetSdkVersion, isSystem); } /** @@ -695,13 +911,15 @@ private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) { */ public static class AppInfo { - private String packageName; - private String name; + private String packageName; + private String name; private Drawable icon; - private String packagePath; - private String versionName; - private int versionCode; - private boolean isSystem; + private String packagePath; + private String versionName; + private int versionCode; + private int minSdkVersion; + private int targetSdkVersion; + private boolean isSystem; public Drawable getIcon() { return icon; @@ -759,18 +977,36 @@ public void setVersionName(final String versionName) { this.versionName = versionName; } - public AppInfo(String packageName, String name, Drawable icon, String packagePath, - String versionName, int versionCode, boolean isSystem) { + public int getMinSdkVersion() { + return minSdkVersion; + } + + public void setMinSdkVersion(int minSdkVersion) { + this.minSdkVersion = minSdkVersion; + } + + public int getTargetSdkVersion() { + return targetSdkVersion; + } + + public void setTargetSdkVersion(int targetSdkVersion) { + this.targetSdkVersion = targetSdkVersion; + } + + public AppInfo(String packageName, String name, Drawable icon, String packagePath, String versionName, int versionCode, int minSdkVersion, int targetSdkVersion, boolean isSystem) { this.setName(name); this.setIcon(icon); this.setPackageName(packageName); this.setPackagePath(packagePath); this.setVersionName(versionName); this.setVersionCode(versionCode); + this.setMinSdkVersion(minSdkVersion); + this.setTargetSdkVersion(targetSdkVersion); this.setSystem(isSystem); } @Override + @NonNull public String toString() { return "{" + "\n pkg name: " + getPackageName() + @@ -779,6 +1015,8 @@ public String toString() { "\n app path: " + getPackagePath() + "\n app v name: " + getVersionName() + "\n app v code: " + getVersionCode() + + "\n app v min: " + getMinSdkVersion() + + "\n app v target: " + getTargetSdkVersion() + "\n is system: " + isSystem() + "\n}"; } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ArrayUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ArrayUtils.java index 08b6142276..48594cedb5 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ArrayUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ArrayUtils.java @@ -8,6 +8,9 @@ import java.util.LinkedList; import java.util.List; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** ** author: blankj @@ -30,39 +33,47 @@ private ArrayUtils() { * @param array The array. * @return a new array only of those given elements. */ - @SafeVarargs + @NonNull public static* - * @param array the array to remove the element from, may not beT[] newArray(T... array) { return array; } + @NonNull public static long[] newLongArray(long... array) { return array; } + @NonNull public static int[] newIntArray(int... array) { return array; } + @NonNull public static short[] newShortArray(short... array) { return array; } + @NonNull public static char[] newCharArray(char... array) { return array; } + @NonNull public static byte[] newByteArray(byte... array) { return array; } + @NonNull public static double[] newDoubleArray(double... array) { return array; } + @NonNull public static float[] newFloatArray(float... array) { return array; } + @NonNull public static boolean[] newBooleanArray(boolean... array) { return array; } @@ -73,7 +84,7 @@ public static boolean[] newBooleanArray(boolean... array) { * @param array The array. * @return {@code true}: yes
{@code false}: no */ - public static boolean isEmpty(Object array) { + public static boolean isEmpty(@Nullable Object array) { return getLength(array) == 0; } @@ -83,12 +94,12 @@ public static boolean isEmpty(Object array) { * @param array The array. * @return the size of array */ - public static int getLength(Object array) { + public static int getLength(@Nullable Object array) { if (array == null) return 0; return Array.getLength(array); } - public static boolean isSameLength(Object array1, Object array2) { + public static boolean isSameLength(@Nullable Object array1, @Nullable Object array2) { return getLength(array1) == getLength(array2); } @@ -99,7 +110,8 @@ public static boolean isSameLength(Object array1, Object array2) { * @param index The index into the array. * @return the value of the specified index of the array */ - public static Object get(Object array, int index) { + @Nullable + public static Object get(@Nullable Object array, int index) { return get(array, index, null); } @@ -111,7 +123,8 @@ public static Object get(Object array, int index) { * @param defaultValue The default value. * @return the value of the specified index of the array */ - public static Object get(Object array, int index, Object defaultValue) { + @Nullable + public static Object get(@Nullable Object array, int index, @Nullable Object defaultValue) { if (array == null) return defaultValue; try { return Array.get(array, index); @@ -127,7 +140,7 @@ public static Object get(Object array, int index, Object defaultValue) { * @param index The index into the array. * @param value The new value of the indexed component. */ - public static void set(Object array, int index, Object value) { + public static void set(@Nullable Object array, int index, @Nullable Object value) { if (array == null) return; Array.set(array, index, value); } @@ -139,7 +152,7 @@ public static void set(Object array, int index, Object value) { * @param a2 The other array. * @return {@code true}: yes
{@code false}: no */ - public static boolean equals(Object[] a, Object[] a2) { + public static boolean equals(@Nullable Object[] a, @Nullable Object[] a2) { return Arrays.deepEquals(a, a2); } @@ -344,52 +357,62 @@ public static void reverse(boolean[] array) { * @param array the array to shallow clone, may benull
* @return the cloned array,null
ifnull
input */ - public staticT[] copy(T[] array) { + @Nullable + public static T[] copy(@Nullable T[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static long[] copy(long[] array) { + @Nullable + public static long[] copy(@Nullable long[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static int[] copy(int[] array) { + @Nullable + public static int[] copy(@Nullable int[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static short[] copy(short[] array) { + @Nullable + public static short[] copy(@Nullable short[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static char[] copy(char[] array) { + @Nullable + public static char[] copy(@Nullable char[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static byte[] copy(byte[] array) { + @Nullable + public static byte[] copy(@Nullable byte[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static double[] copy(double[] array) { + @Nullable + public static double[] copy(@Nullable double[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static float[] copy(float[] array) { + @Nullable + public static float[] copy(@Nullable float[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - public static boolean[] copy(boolean[] array) { + @Nullable + public static boolean[] copy(@Nullable boolean[] array) { if (array == null) return null; return subArray(array, 0, array.length); } - private static Object realCopy(Object array) { + @Nullable + private static Object realCopy(@Nullable Object array) { if (array == null) return null; return realSubArray(array, 0, getLength(array)); } @@ -398,44 +421,54 @@ private static Object realCopy(Object array) { // subArray /////////////////////////////////////////////////////////////////////////// - public static T[] subArray(T[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static T[] subArray(@Nullable T[] array, int startIndexInclusive, int endIndexExclusive) { //noinspection unchecked return (T[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static long[] subArray(long[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static long[] subArray(@Nullable long[] array, int startIndexInclusive, int endIndexExclusive) { return (long[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static int[] subArray(int[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static int[] subArray(@Nullable int[] array, int startIndexInclusive, int endIndexExclusive) { return (int[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static short[] subArray(short[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static short[] subArray(@Nullable short[] array, int startIndexInclusive, int endIndexExclusive) { return (short[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static char[] subArray(char[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static char[] subArray(@Nullable char[] array, int startIndexInclusive, int endIndexExclusive) { return (char[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static byte[] subArray(byte[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static byte[] subArray(@Nullable byte[] array, int startIndexInclusive, int endIndexExclusive) { return (byte[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static double[] subArray(double[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static double[] subArray(@Nullable double[] array, int startIndexInclusive, int endIndexExclusive) { return (double[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static float[] subArray(float[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static float[] subArray(@Nullable float[] array, int startIndexInclusive, int endIndexExclusive) { return (float[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - public static boolean[] subArray(boolean[] array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + public static boolean[] subArray(@Nullable boolean[] array, int startIndexInclusive, int endIndexExclusive) { return (boolean[]) realSubArray(array, startIndexInclusive, endIndexExclusive); } - private static Object realSubArray(Object array, int startIndexInclusive, int endIndexExclusive) { + @Nullable + private static Object realSubArray(@Nullable Object array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } @@ -482,44 +515,54 @@ private static Object realSubArray(Object array, int startIndexInclusive, int en * @param element the object to realAdd * @return A new array containing the existing elements plus the new element */ - public static T[] add(T[] array, T element) { + @NonNull + public static T[] add(@Nullable T[] array, @Nullable T element) { Class type = array != null ? array.getClass() : (element != null ? element.getClass() : Object.class); return (T[]) realAddOne(array, element, type); } - public static boolean[] add(boolean[] array, boolean element) { + @NonNull + public static boolean[] add(@Nullable boolean[] array, boolean element) { return (boolean[]) realAddOne(array, element, Boolean.TYPE); } - public static byte[] add(byte[] array, byte element) { + @NonNull + public static byte[] add(@Nullable byte[] array, byte element) { return (byte[]) realAddOne(array, element, Byte.TYPE); } - public static char[] add(char[] array, char element) { + @NonNull + public static char[] add(@Nullable char[] array, char element) { return (char[]) realAddOne(array, element, Character.TYPE); } - public static double[] add(double[] array, double element) { + @NonNull + public static double[] add(@Nullable double[] array, double element) { return (double[]) realAddOne(array, element, Double.TYPE); } - public static float[] add(float[] array, float element) { + @NonNull + public static float[] add(@Nullable float[] array, float element) { return (float[]) realAddOne(array, element, Float.TYPE); } - public static int[] add(int[] array, int element) { + @NonNull + public static int[] add(@Nullable int[] array, int element) { return (int[]) realAddOne(array, element, Integer.TYPE); } - public static long[] add(long[] array, long element) { + @NonNull + public static long[] add(@Nullable long[] array, long element) { return (long[]) realAddOne(array, element, Long.TYPE); } - public static short[] add(short[] array, short element) { + @NonNull + public static short[] add(@Nullable short[] array, short element) { return (short[]) realAddOne(array, element, Short.TYPE); } - private static Object realAddOne(Object array, Object element, Class newArrayComponentType) { + @NonNull + private static Object realAddOne(@Nullable Object array, @Nullable Object element, Class newArrayComponentType) { Object newArray; int arrayLength = 0; if (array != null) { @@ -553,43 +596,52 @@ private static Object realAddOne(Object array, Object element, Class newArrayCom * @return The new array, null
ifnull
array inputs. * The type of the new array is the type of the first array. */ - public staticT[] add(T[] array1, T[] array2) { + @Nullable + public static T[] add(@Nullable T[] array1, @Nullable T[] array2) { return (T[]) realAddArr(array1, array2); } - public static boolean[] add(boolean[] array1, boolean[] array2) { + @Nullable + public static boolean[] add(@Nullable boolean[] array1, @Nullable boolean[] array2) { return (boolean[]) realAddArr(array1, array2); } - public static char[] add(char[] array1, char[] array2) { + @Nullable + public static char[] add(@Nullable char[] array1, @Nullable char[] array2) { return (char[]) realAddArr(array1, array2); } - public static byte[] add(byte[] array1, byte[] array2) { + @Nullable + public static byte[] add(@Nullable byte[] array1, @Nullable byte[] array2) { return (byte[]) realAddArr(array1, array2); } - public static short[] add(short[] array1, short[] array2) { + @Nullable + public static short[] add(@Nullable short[] array1, @Nullable short[] array2) { return (short[]) realAddArr(array1, array2); } - public static int[] add(int[] array1, int[] array2) { + @Nullable + public static int[] add(@Nullable int[] array1, @Nullable int[] array2) { return (int[]) realAddArr(array1, array2); } - public static long[] add(long[] array1, long[] array2) { + @Nullable + public static long[] add(@Nullable long[] array1, @Nullable long[] array2) { return (long[]) realAddArr(array1, array2); } - public static float[] add(float[] array1, float[] array2) { + @Nullable + public static float[] add(@Nullable float[] array1, @Nullable float[] array2) { return (float[]) realAddArr(array1, array2); } - public static double[] add(double[] array1, double[] array2) { + @Nullable + public static double[] add(@Nullable double[] array1, @Nullable double[] array2) { return (double[]) realAddArr(array1, array2); } - private static Object realAddArr(Object array1, Object array2) { + private static Object realAddArr(@Nullable Object array1, @Nullable Object array2) { if (array1 == null && array2 == null) return null; if (array1 == null) { return realCopy(array2); @@ -619,11 +671,11 @@ private static Object realAddArr(Object array1, Object array2) { * whose component type is the same as the element. * * - * ArrayUtils.add(null, 0, null) = [null] - * ArrayUtils.add(null, 0, "a") = ["a"] - * ArrayUtils.add(["a"], 1, null) = ["a", null] - * ArrayUtils.add(["a"], 1, "b") = ["a", "b"] - * ArrayUtils.add(["a", "b"], 3, "c") = ["a", "b", "c"] + * ArrayUtils.add(null, 0, null) = null + * ArrayUtils.add(null, 0, ["a"]) = ["a"] + * ArrayUtils.add(["a"], 1, null) = ["a"] + * ArrayUtils.add(["a"], 1, ["b"]) = ["a", "b"] + * ArrayUtils.add(["a", "b"], 2, ["c"]) = ["a", "b", "c"] ** * @param array1 the array to realAdd the element to, may benull
@@ -633,51 +685,76 @@ private static Object realAddArr(Object array1, Object array2) { * @throws IndexOutOfBoundsException if the index is out of range * (index < 0 || index > array.length). */ - public staticT[] add(T[] array1, int index, T[] array2) { + @Nullable + public static T[] add(@Nullable T[] array1, int index, @Nullable T[] array2) { Class clss; if (array1 != null) { clss = array1.getClass().getComponentType(); } else if (array2 != null) { clss = array2.getClass().getComponentType(); } else { - return (T[]) new Object[]{null}; + return null; } return (T[]) realAddArr(array1, index, array2, clss); } - public static boolean[] add(boolean[] array1, int index, boolean[] array2) { - return (boolean[]) realAddArr(array1, index, array2, Boolean.TYPE); + @Nullable + public static boolean[] add(@Nullable boolean[] array1, int index, @Nullable boolean[] array2) { + Object result = realAddArr(array1, index, array2, Boolean.TYPE); + if (result == null) return null; + return (boolean[]) result; } - public static char[] add(char[] array1, int index, char[] array2) { - return (char[]) realAddArr(array1, index, array2, Character.TYPE); + public static char[] add(@Nullable char[] array1, int index, @Nullable char[] array2) { + Object result = realAddArr(array1, index, array2, Character.TYPE); + if (result == null) return null; + return (char[]) result; } - public static byte[] add(byte[] array1, int index, byte[] array2) { - return (byte[]) realAddArr(array1, index, array2, Byte.TYPE); + @Nullable + public static byte[] add(@Nullable byte[] array1, int index, @Nullable byte[] array2) { + Object result = realAddArr(array1, index, array2, Byte.TYPE); + if (result == null) return null; + return (byte[]) result; } - public static short[] add(short[] array1, int index, short[] array2) { - return (short[]) realAddArr(array1, index, array2, Short.TYPE); + @Nullable + public static short[] add(@Nullable short[] array1, int index, @Nullable short[] array2) { + Object result = realAddArr(array1, index, array2, Short.TYPE); + if (result == null) return null; + return (short[]) result; } - public static int[] add(int[] array1, int index, int[] array2) { - return (int[]) realAddArr(array1, index, array2, Integer.TYPE); + @Nullable + public static int[] add(@Nullable int[] array1, int index, @Nullable int[] array2) { + Object result = realAddArr(array1, index, array2, Integer.TYPE); + if (result == null) return null; + return (int[]) result; } - public static long[] add(long[] array1, int index, long[] array2) { - return (long[]) realAddArr(array1, index, array2, Long.TYPE); + @Nullable + public static long[] add(@Nullable long[] array1, int index, @Nullable long[] array2) { + Object result = realAddArr(array1, index, array2, Long.TYPE); + if (result == null) return null; + return (long[]) result; } - public static float[] add(float[] array1, int index, float[] array2) { - return (float[]) realAddArr(array1, index, array2, Float.TYPE); + @Nullable + public static float[] add(@Nullable float[] array1, int index, @Nullable float[] array2) { + Object result = realAddArr(array1, index, array2, Float.TYPE); + if (result == null) return null; + return (float[]) result; } - public static double[] add(double[] array1, int index, double[] array2) { - return (double[]) realAddArr(array1, index, array2, Double.TYPE); + @Nullable + public static double[] add(@Nullable double[] array1, int index, @Nullable double[] array2) { + Object result = realAddArr(array1, index, array2, Double.TYPE); + if (result == null) return null; + return (double[]) result; } - private static Object realAddArr(Object array1, int index, Object array2, Class clss) { + @Nullable + private static Object realAddArr(@Nullable Object array1, int index, @Nullable Object array2, Class clss) { if (array1 == null && array2 == null) return null; int len1 = getLength(array1); int len2 = getLength(array2); @@ -736,7 +813,8 @@ private static Object realAddArr(Object array1, int index, Object array2, Class * @throws IndexOutOfBoundsException if the index is out of range * (index < 0 || index > array.length). */ - public static T[] add(T[] array, int index, T element) { + @NonNull + public static T[] add(@Nullable T[] array, int index, @Nullable T element) { Class clss; if (array != null) { clss = array.getClass().getComponentType(); @@ -748,39 +826,48 @@ public static T[] add(T[] array, int index, T element) { return (T[]) realAdd(array, index, element, clss); } - public static boolean[] add(boolean[] array, int index, boolean element) { + @NonNull + public static boolean[] add(@Nullable boolean[] array, int index, boolean element) { return (boolean[]) realAdd(array, index, element, Boolean.TYPE); } - public static char[] add(char[] array, int index, char element) { + @NonNull + public static char[] add(@Nullable char[] array, int index, char element) { return (char[]) realAdd(array, index, element, Character.TYPE); } - public static byte[] add(byte[] array, int index, byte element) { + @NonNull + public static byte[] add(@Nullable byte[] array, int index, byte element) { return (byte[]) realAdd(array, index, element, Byte.TYPE); } - public static short[] add(short[] array, int index, short element) { + @NonNull + public static short[] add(@Nullable short[] array, int index, short element) { return (short[]) realAdd(array, index, element, Short.TYPE); } - public static int[] add(int[] array, int index, int element) { + @NonNull + public static int[] add(@Nullable int[] array, int index, int element) { return (int[]) realAdd(array, index, element, Integer.TYPE); } - public static long[] add(long[] array, int index, long element) { + @NonNull + public static long[] add(@Nullable long[] array, int index, long element) { return (long[]) realAdd(array, index, element, Long.TYPE); } - public static float[] add(float[] array, int index, float element) { + @NonNull + public static float[] add(@Nullable float[] array, int index, float element) { return (float[]) realAdd(array, index, element, Float.TYPE); } - public static double[] add(double[] array, int index, double element) { + @NonNull + public static double[] add(@Nullable double[] array, int index, double element) { return (double[]) realAdd(array, index, element, Double.TYPE); } - private static Object realAdd(Object array, int index, Object element, Class clss) { + @NonNull + private static Object realAdd(@Nullable Object array, int index, @Nullable Object element, Class clss) { if (array == null) { if (index != 0) { throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0"); @@ -826,15 +913,16 @@ private static Object realAdd(Object array, int index, Object element, Class cls * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"] * null
+ * @param array the array to remove the element from, may benull
* @param index the position of the element to be removed * @return A new array containing the existing elements except the element * at the specified position. * @throws IndexOutOfBoundsException if the index is out of range - * (index < 0 || index >= array.length), or if the array isnull
. - * @since 2.1 + * (index < 0 || index >= array.length) */ - public static Object[] remove(Object[] array, int index) { + @Nullable + public static Object[] remove(@Nullable Object[] array, int index) { + if (array == null) return null; return (Object[]) remove((Object) array, index); } @@ -861,9 +949,9 @@ public static Object[] remove(Object[] array, int index) { * @param element the element to be removed * @return A new array containing the existing elements except the first * occurrence of the specified element. - * @since 2.1 */ - public static Object[] removeElement(Object[] array, Object element) { + @Nullable + public static Object[] removeElement(@Nullable Object[] array, @Nullable Object element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -871,11 +959,14 @@ public static Object[] removeElement(Object[] array, Object element) { return remove(array, index); } - public static boolean[] remove(boolean[] array, int index) { + @Nullable + public static boolean[] remove(@Nullable boolean[] array, int index) { + if (array == null) return null; return (boolean[]) remove((Object) array, index); } - public static boolean[] removeElement(boolean[] array, boolean element) { + @Nullable + public static boolean[] removeElement(@Nullable boolean[] array, boolean element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -883,11 +974,14 @@ public static boolean[] removeElement(boolean[] array, boolean element) { return remove(array, index); } - public static byte[] remove(byte[] array, int index) { + @Nullable + public static byte[] remove(@Nullable byte[] array, int index) { + if (array == null) return null; return (byte[]) remove((Object) array, index); } - public static byte[] removeElement(byte[] array, byte element) { + @Nullable + public static byte[] removeElement(@Nullable byte[] array, byte element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -895,11 +989,14 @@ public static byte[] removeElement(byte[] array, byte element) { return remove(array, index); } - public static char[] remove(char[] array, int index) { + @Nullable + public static char[] remove(@Nullable char[] array, int index) { + if (array == null) return null; return (char[]) remove((Object) array, index); } - public static char[] removeElement(char[] array, char element) { + @Nullable + public static char[] removeElement(@Nullable char[] array, char element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -907,23 +1004,30 @@ public static char[] removeElement(char[] array, char element) { return remove(array, index); } - public static double[] remove(double[] array, int index) { + @Nullable + public static double[] remove(@Nullable double[] array, int index) { + if (array == null) return null; return (double[]) remove((Object) array, index); } - public static double[] removeElement(double[] array, double element) { + @Nullable + public static double[] removeElement(@Nullable double[] array, double element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); } + //noinspection ConstantConditions return remove(array, index); } - public static float[] remove(float[] array, int index) { + @Nullable + public static float[] remove(@Nullable float[] array, int index) { + if (array == null) return null; return (float[]) remove((Object) array, index); } - public static float[] removeElement(float[] array, float element) { + @Nullable + public static float[] removeElement(@Nullable float[] array, float element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -931,11 +1035,14 @@ public static float[] removeElement(float[] array, float element) { return remove(array, index); } - public static int[] remove(int[] array, int index) { + @Nullable + public static int[] remove(@Nullable int[] array, int index) { + if (array == null) return null; return (int[]) remove((Object) array, index); } - public static int[] removeElement(int[] array, int element) { + @Nullable + public static int[] removeElement(@Nullable int[] array, int element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -943,11 +1050,14 @@ public static int[] removeElement(int[] array, int element) { return remove(array, index); } - public static long[] remove(long[] array, int index) { + @Nullable + public static long[] remove(@Nullable long[] array, int index) { + if (array == null) return null; return (long[]) remove((Object) array, index); } - public static long[] removeElement(long[] array, long element) { + @Nullable + public static long[] removeElement(@Nullable long[] array, long element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -955,11 +1065,14 @@ public static long[] removeElement(long[] array, long element) { return remove(array, index); } - public static short[] remove(short[] array, int index) { + @Nullable + public static short[] remove(@Nullable short[] array, int index) { + if (array == null) return null; return (short[]) remove((Object) array, index); } - public static short[] removeElement(short[] array, short element) { + @Nullable + public static short[] removeElement(@Nullable short[] array, short element) { int index = indexOf(array, element); if (index == INDEX_NOT_FOUND) { return copy(array); @@ -967,7 +1080,8 @@ public static short[] removeElement(short[] array, short element) { return remove(array, index); } - private static Object remove(Object array, int index) { + @NonNull + private static Object remove(@NonNull Object array, int index) { int length = getLength(array); if (index < 0 || index >= length) { throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length); @@ -986,11 +1100,11 @@ private static Object remove(Object array, int index) { // object indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(Object[] array, Object objectToFind) { + public static int indexOf(@Nullable Object[] array, @Nullable Object objectToFind) { return indexOf(array, objectToFind, 0); } - public static int indexOf(Object[] array, final Object objectToFind, int startIndex) { + public static int indexOf(@Nullable Object[] array, @Nullable final Object objectToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1013,11 +1127,11 @@ public static int indexOf(Object[] array, final Object objectToFind, int startIn return INDEX_NOT_FOUND; } - public static int lastIndexOf(Object[] array, Object objectToFind) { + public static int lastIndexOf(@Nullable Object[] array, @Nullable Object objectToFind) { return lastIndexOf(array, objectToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(Object[] array, Object objectToFind, int startIndex) { + public static int lastIndexOf(@Nullable Object[] array, @Nullable Object objectToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1042,7 +1156,7 @@ public static int lastIndexOf(Object[] array, Object objectToFind, int startInde return INDEX_NOT_FOUND; } - public static boolean contains(Object[] array, Object objectToFind) { + public static boolean contains(@Nullable Object[] array, @Nullable Object objectToFind) { return indexOf(array, objectToFind) != INDEX_NOT_FOUND; } @@ -1050,11 +1164,11 @@ public static boolean contains(Object[] array, Object objectToFind) { // long indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(long[] array, long valueToFind) { + public static int indexOf(@Nullable long[] array, long valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(long[] array, long valueToFind, int startIndex) { + public static int indexOf(@Nullable long[] array, long valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1069,11 +1183,11 @@ public static int indexOf(long[] array, long valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int lastIndexOf(long[] array, long valueToFind) { + public static int lastIndexOf(@Nullable long[] array, long valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(long[] array, long valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable long[] array, long valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1090,7 +1204,7 @@ public static int lastIndexOf(long[] array, long valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static boolean contains(long[] array, long valueToFind) { + public static boolean contains(@Nullable long[] array, long valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1098,11 +1212,11 @@ public static boolean contains(long[] array, long valueToFind) { // int indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(int[] array, int valueToFind) { + public static int indexOf(@Nullable int[] array, int valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(int[] array, int valueToFind, int startIndex) { + public static int indexOf(@Nullable int[] array, int valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1117,11 +1231,11 @@ public static int indexOf(int[] array, int valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int lastIndexOf(int[] array, int valueToFind) { + public static int lastIndexOf(@Nullable int[] array, int valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(int[] array, int valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable int[] array, int valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1138,7 +1252,7 @@ public static int lastIndexOf(int[] array, int valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static boolean contains(int[] array, int valueToFind) { + public static boolean contains(@Nullable int[] array, int valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1146,11 +1260,11 @@ public static boolean contains(int[] array, int valueToFind) { // short indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(short[] array, short valueToFind) { + public static int indexOf(@Nullable short[] array, short valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(short[] array, short valueToFind, int startIndex) { + public static int indexOf(@Nullable short[] array, short valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1165,11 +1279,11 @@ public static int indexOf(short[] array, short valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int lastIndexOf(short[] array, short valueToFind) { + public static int lastIndexOf(@Nullable short[] array, short valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(short[] array, short valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable short[] array, short valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1186,7 +1300,7 @@ public static int lastIndexOf(short[] array, short valueToFind, int startIndex) return INDEX_NOT_FOUND; } - public static boolean contains(short[] array, short valueToFind) { + public static boolean contains(@Nullable short[] array, short valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1194,11 +1308,11 @@ public static boolean contains(short[] array, short valueToFind) { // char indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(char[] array, char valueToFind) { + public static int indexOf(@Nullable char[] array, char valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(char[] array, char valueToFind, int startIndex) { + public static int indexOf(@Nullable char[] array, char valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1213,11 +1327,11 @@ public static int indexOf(char[] array, char valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int lastIndexOf(char[] array, char valueToFind) { + public static int lastIndexOf(@Nullable char[] array, char valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(char[] array, char valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable char[] array, char valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1234,7 +1348,7 @@ public static int lastIndexOf(char[] array, char valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static boolean contains(char[] array, char valueToFind) { + public static boolean contains(@Nullable char[] array, char valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1242,11 +1356,11 @@ public static boolean contains(char[] array, char valueToFind) { // byte indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(byte[] array, byte valueToFind) { + public static int indexOf(@Nullable byte[] array, byte valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(byte[] array, byte valueToFind, int startIndex) { + public static int indexOf(@Nullable byte[] array, byte valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1261,11 +1375,11 @@ public static int indexOf(byte[] array, byte valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int lastIndexOf(byte[] array, byte valueToFind) { + public static int lastIndexOf(@Nullable byte[] array, byte valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(byte[] array, byte valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable byte[] array, byte valueToFind, int startIndex) { if (array == null) { return INDEX_NOT_FOUND; } @@ -1282,7 +1396,7 @@ public static int lastIndexOf(byte[] array, byte valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static boolean contains(byte[] array, byte valueToFind) { + public static boolean contains(@Nullable byte[] array, byte valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1290,15 +1404,15 @@ public static boolean contains(byte[] array, byte valueToFind) { // double indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(double[] array, double valueToFind) { + public static int indexOf(@Nullable double[] array, double valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(double[] array, double valueToFind, double tolerance) { + public static int indexOf(@Nullable double[] array, double valueToFind, double tolerance) { return indexOf(array, valueToFind, 0, tolerance); } - public static int indexOf(double[] array, double valueToFind, int startIndex) { + public static int indexOf(@Nullable double[] array, double valueToFind, int startIndex) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1313,7 +1427,7 @@ public static int indexOf(double[] array, double valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int indexOf(double[] array, double valueToFind, int startIndex, double tolerance) { + public static int indexOf(@Nullable double[] array, double valueToFind, int startIndex, double tolerance) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1330,15 +1444,15 @@ public static int indexOf(double[] array, double valueToFind, int startIndex, do return INDEX_NOT_FOUND; } - public static int lastIndexOf(double[] array, double valueToFind) { + public static int lastIndexOf(@Nullable double[] array, double valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(double[] array, double valueToFind, double tolerance) { + public static int lastIndexOf(@Nullable double[] array, double valueToFind, double tolerance) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance); } - public static int lastIndexOf(double[] array, double valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable double[] array, double valueToFind, int startIndex) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1355,7 +1469,7 @@ public static int lastIndexOf(double[] array, double valueToFind, int startIndex return INDEX_NOT_FOUND; } - public static int lastIndexOf(double[] array, double valueToFind, int startIndex, double tolerance) { + public static int lastIndexOf(@Nullable double[] array, double valueToFind, int startIndex, double tolerance) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1374,11 +1488,11 @@ public static int lastIndexOf(double[] array, double valueToFind, int startIndex return INDEX_NOT_FOUND; } - public static boolean contains(double[] array, double valueToFind) { + public static boolean contains(@Nullable double[] array, double valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } - public static boolean contains(double[] array, double valueToFind, double tolerance) { + public static boolean contains(@Nullable double[] array, double valueToFind, double tolerance) { return indexOf(array, valueToFind, 0, tolerance) != INDEX_NOT_FOUND; } @@ -1386,11 +1500,11 @@ public static boolean contains(double[] array, double valueToFind, double tolera // float indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(float[] array, float valueToFind) { + public static int indexOf(@Nullable float[] array, float valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(float[] array, float valueToFind, int startIndex) { + public static int indexOf(@Nullable float[] array, float valueToFind, int startIndex) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1405,11 +1519,11 @@ public static int indexOf(float[] array, float valueToFind, int startIndex) { return INDEX_NOT_FOUND; } - public static int lastIndexOf(float[] array, float valueToFind) { + public static int lastIndexOf(@Nullable float[] array, float valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(float[] array, float valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable float[] array, float valueToFind, int startIndex) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1426,7 +1540,7 @@ public static int lastIndexOf(float[] array, float valueToFind, int startIndex) return INDEX_NOT_FOUND; } - public static boolean contains(float[] array, float valueToFind) { + public static boolean contains(@Nullable float[] array, float valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1434,11 +1548,11 @@ public static boolean contains(float[] array, float valueToFind) { // bool indexOf /////////////////////////////////////////////////////////////////////////// - public static int indexOf(boolean[] array, boolean valueToFind) { + public static int indexOf(@Nullable boolean[] array, boolean valueToFind) { return indexOf(array, valueToFind, 0); } - public static int indexOf(boolean[] array, boolean valueToFind, int startIndex) { + public static int indexOf(@Nullable boolean[] array, boolean valueToFind, int startIndex) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1453,11 +1567,11 @@ public static int indexOf(boolean[] array, boolean valueToFind, int startIndex) return INDEX_NOT_FOUND; } - public static int lastIndexOf(boolean[] array, boolean valueToFind) { + public static int lastIndexOf(@Nullable boolean[] array, boolean valueToFind) { return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); } - public static int lastIndexOf(boolean[] array, boolean valueToFind, int startIndex) { + public static int lastIndexOf(@Nullable boolean[] array, boolean valueToFind, int startIndex) { if (ArrayUtils.isEmpty(array)) { return INDEX_NOT_FOUND; } @@ -1474,7 +1588,7 @@ public static int lastIndexOf(boolean[] array, boolean valueToFind, int startInd return INDEX_NOT_FOUND; } - public static boolean contains(boolean[] array, boolean valueToFind) { + public static boolean contains(@Nullable boolean[] array, boolean valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } @@ -1482,7 +1596,8 @@ public static boolean contains(boolean[] array, boolean valueToFind) { // char converters /////////////////////////////////////////////////////////////////////////// - public static char[] toPrimitive(Character[] array) { + @Nullable + public static char[] toPrimitive(@Nullable Character[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1495,7 +1610,8 @@ public static char[] toPrimitive(Character[] array) { return result; } - public static char[] toPrimitive(Character[] array, char valueForNull) { + @Nullable + public static char[] toPrimitive(@Nullable Character[] array, char valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1509,7 +1625,8 @@ public static char[] toPrimitive(Character[] array, char valueForNull) { return result; } - public static Character[] toObject(char[] array) { + @Nullable + public static Character[] toObject(@Nullable char[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1526,7 +1643,8 @@ public static Character[] toObject(char[] array) { // long converters /////////////////////////////////////////////////////////////////////////// - public static long[] toPrimitive(Long[] array) { + @Nullable + public static long[] toPrimitive(@Nullable Long[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1539,7 +1657,8 @@ public static long[] toPrimitive(Long[] array) { return result; } - public static long[] toPrimitive(Long[] array, long valueForNull) { + @Nullable + public static long[] toPrimitive(@Nullable Long[] array, long valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1553,7 +1672,8 @@ public static long[] toPrimitive(Long[] array, long valueForNull) { return result; } - public static Long[] toObject(long[] array) { + @Nullable + public static Long[] toObject(@Nullable long[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1570,7 +1690,8 @@ public static Long[] toObject(long[] array) { // int converters /////////////////////////////////////////////////////////////////////////// - public static int[] toPrimitive(Integer[] array) { + @Nullable + public static int[] toPrimitive(@Nullable Integer[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1583,7 +1704,8 @@ public static int[] toPrimitive(Integer[] array) { return result; } - public static int[] toPrimitive(Integer[] array, int valueForNull) { + @Nullable + public static int[] toPrimitive(@Nullable Integer[] array, int valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1597,7 +1719,8 @@ public static int[] toPrimitive(Integer[] array, int valueForNull) { return result; } - public static Integer[] toObject(int[] array) { + @Nullable + public static Integer[] toObject(@Nullable int[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1614,7 +1737,8 @@ public static Integer[] toObject(int[] array) { // short converters /////////////////////////////////////////////////////////////////////////// - public static short[] toPrimitive(Short[] array) { + @Nullable + public static short[] toPrimitive(@Nullable Short[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1627,7 +1751,8 @@ public static short[] toPrimitive(Short[] array) { return result; } - public static short[] toPrimitive(Short[] array, short valueForNull) { + @Nullable + public static short[] toPrimitive(@Nullable Short[] array, short valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1641,7 +1766,8 @@ public static short[] toPrimitive(Short[] array, short valueForNull) { return result; } - public static Short[] toObject(short[] array) { + @Nullable + public static Short[] toObject(@Nullable short[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1658,7 +1784,8 @@ public static Short[] toObject(short[] array) { // byte converters /////////////////////////////////////////////////////////////////////////// - public static byte[] toPrimitive(Byte[] array) { + @Nullable + public static byte[] toPrimitive(@Nullable Byte[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1671,7 +1798,8 @@ public static byte[] toPrimitive(Byte[] array) { return result; } - public static byte[] toPrimitive(Byte[] array, byte valueForNull) { + @Nullable + public static byte[] toPrimitive(@Nullable Byte[] array, byte valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1685,7 +1813,8 @@ public static byte[] toPrimitive(Byte[] array, byte valueForNull) { return result; } - public static Byte[] toObject(byte[] array) { + @Nullable + public static Byte[] toObject(@Nullable byte[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1702,7 +1831,8 @@ public static Byte[] toObject(byte[] array) { // double converters /////////////////////////////////////////////////////////////////////////// - public static double[] toPrimitive(Double[] array) { + @Nullable + public static double[] toPrimitive(@Nullable Double[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1715,7 +1845,8 @@ public static double[] toPrimitive(Double[] array) { return result; } - public static double[] toPrimitive(Double[] array, double valueForNull) { + @Nullable + public static double[] toPrimitive(@Nullable Double[] array, double valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1729,7 +1860,8 @@ public static double[] toPrimitive(Double[] array, double valueForNull) { return result; } - public static Double[] toObject(double[] array) { + @Nullable + public static Double[] toObject(@Nullable double[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1746,7 +1878,8 @@ public static Double[] toObject(double[] array) { // float converters /////////////////////////////////////////////////////////////////////////// - public static float[] toPrimitive(Float[] array) { + @Nullable + public static float[] toPrimitive(@Nullable Float[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1759,7 +1892,8 @@ public static float[] toPrimitive(Float[] array) { return result; } - public static float[] toPrimitive(Float[] array, float valueForNull) { + @Nullable + public static float[] toPrimitive(@Nullable Float[] array, float valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1773,7 +1907,8 @@ public static float[] toPrimitive(Float[] array, float valueForNull) { return result; } - public static Float[] toObject(float[] array) { + @Nullable + public static Float[] toObject(@Nullable float[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1790,7 +1925,8 @@ public static Float[] toObject(float[] array) { // boolean converters /////////////////////////////////////////////////////////////////////////// - public static boolean[] toPrimitive(Boolean[] array) { + @Nullable + public static boolean[] toPrimitive(@Nullable Boolean[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1803,7 +1939,8 @@ public static boolean[] toPrimitive(Boolean[] array) { return result; } - public static boolean[] toPrimitive(Boolean[] array, boolean valueForNull) { + @Nullable + public static boolean[] toPrimitive(@Nullable Boolean[] array, boolean valueForNull) { if (array == null) { return null; } else if (array.length == 0) { @@ -1817,7 +1954,8 @@ public static boolean[] toPrimitive(Boolean[] array, boolean valueForNull) { return result; } - public static Boolean[] toObject(boolean[] array) { + @Nullable + public static Boolean[] toObject(@Nullable boolean[] array) { if (array == null) { return null; } else if (array.length == 0) { @@ -1830,67 +1968,71 @@ public static Boolean[] toObject(boolean[] array) { return result; } - public staticList asList(T... array) { + @NonNull + public static List asList(@Nullable T... array) { if (array == null || array.length == 0) { return Collections.emptyList(); } return Arrays.asList(array); } - public static List asUnmodifiableList(T... array) { + @NonNull + public static List asUnmodifiableList(@Nullable T... array) { return Collections.unmodifiableList(asList(array)); } - public static List asArrayList(T... array) { + @NonNull + public static List asArrayList(@Nullable T... array) { List list = new ArrayList<>(); if (array == null || array.length == 0) return list; list.addAll(Arrays.asList(array)); return list; } - public static List asLinkedList(T... array) { + @NonNull + public static List asLinkedList(@Nullable T... array) { List list = new LinkedList<>(); if (array == null || array.length == 0) return list; list.addAll(Arrays.asList(array)); return list; } - public static void sort(T[] array, Comparator super T> c) { + public static void sort(@Nullable T[] array, Comparator super T> c) { if (array == null || array.length < 2) return; Arrays.sort(array, c); } - public static void sort(byte[] array) { + public static void sort(@Nullable byte[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } - public static void sort(char[] array) { + public static void sort(@Nullable char[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } - public static void sort(double[] array) { + public static void sort(@Nullable double[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } - public static void sort(float[] array) { + public static void sort(@Nullable float[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } - public static void sort(int[] array) { + public static void sort(@Nullable int[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } - public static void sort(long[] array) { + public static void sort(@Nullable long[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } - public static void sort(short[] array) { + public static void sort(@Nullable short[] array) { if (array == null || array.length < 2) return; Arrays.sort(array); } @@ -1903,7 +2045,7 @@ public static void sort(short[] array) { * @param array The array. * @param closure the closure to perform, may be null */ - public static void forAllDo(Object array, Closure closure) { + public static void forAllDo(@Nullable Object array, @Nullable Closure closure) { if (array == null || closure == null) return; if (array instanceof Object[]) { Object[] objects = (Object[]) array; @@ -1970,7 +2112,8 @@ public static void forAllDo(Object array, Closure closure) { * @param array The array. * @return the string of array */ - public static String toString(Object array) { + @NonNull + public static String toString(@Nullable Object array) { if (array == null) return "null"; if (array instanceof Object[]) { return Arrays.deepToString((Object[]) array); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/BarUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/BarUtils.java index 0350dacdbb..e8cacc5f0c 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/BarUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/BarUtils.java @@ -1,5 +1,7 @@ package com.blankj.utilcode.util; +import static android.Manifest.permission.EXPAND_STATUS_BAR; + import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; @@ -7,11 +9,7 @@ import android.graphics.Color; import android.graphics.Point; import android.os.Build; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; -import android.support.annotation.RequiresPermission; -import android.support.v4.widget.DrawerLayout; +import android.provider.Settings; import android.util.TypedValue; import android.view.Display; import android.view.KeyCharacterMap; @@ -23,9 +21,13 @@ import android.view.Window; import android.view.WindowManager; -import java.lang.reflect.Method; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; +import androidx.drawerlayout.widget.DrawerLayout; -import static android.Manifest.permission.EXPAND_STATUS_BAR; +import java.lang.reflect.Method; /** * @@ -42,8 +44,8 @@ public final class BarUtils { /////////////////////////////////////////////////////////////////////////// private static final String TAG_STATUS_BAR = "TAG_STATUS_BAR"; - private static final String TAG_OFFSET = "TAG_OFFSET"; - private static final int KEY_OFFSET = -123; + private static final String TAG_OFFSET = "TAG_OFFSET"; + private static final int KEY_OFFSET = -123; private BarUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); @@ -192,14 +194,14 @@ public static void subtractMarginTopEqualStatusBarHeight(@NonNull View view) { view.setTag(KEY_OFFSET, false); } - private static void addMarginTopEqualStatusBarHeight(final Window window) { + private static void addMarginTopEqualStatusBarHeight(@NonNull final Window window) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); if (withTag == null) return; addMarginTopEqualStatusBarHeight(withTag); } - private static void subtractMarginTopEqualStatusBarHeight(final Window window) { + private static void subtractMarginTopEqualStatusBarHeight(@NonNull final Window window) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); if (withTag == null) return; @@ -347,13 +349,13 @@ public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, } } - private static View applyStatusBarColor(final Activity activity, + private static View applyStatusBarColor(@NonNull final Activity activity, final int color, boolean isDecor) { return applyStatusBarColor(activity.getWindow(), color, isDecor); } - private static View applyStatusBarColor(final Window window, + private static View applyStatusBarColor(@NonNull final Window window, final int color, boolean isDecor) { ViewGroup parent = isDecor ? @@ -372,25 +374,25 @@ private static View applyStatusBarColor(final Window window, return fakeStatusBarView; } - private static void hideStatusBarView(final Activity activity) { + private static void hideStatusBarView(@NonNull final Activity activity) { hideStatusBarView(activity.getWindow()); } - private static void hideStatusBarView(final Window window) { + private static void hideStatusBarView(@NonNull final Window window) { ViewGroup decorView = (ViewGroup) window.getDecorView(); View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); if (fakeStatusBarView == null) return; fakeStatusBarView.setVisibility(View.GONE); } - private static void showStatusBarView(final Window window) { + private static void showStatusBarView(@NonNull final Window window) { ViewGroup decorView = (ViewGroup) window.getDecorView(); View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); if (fakeStatusBarView == null) return; fakeStatusBarView.setVisibility(View.VISIBLE); } - private static View createStatusBarView(final Context context, + private static View createStatusBarView(@NonNull final Context context, final int color) { View statusBarView = new View(context); statusBarView.setLayoutParams(new ViewGroup.LayoutParams( @@ -400,11 +402,11 @@ private static View createStatusBarView(final Context context, return statusBarView; } - public static void transparentStatusBar(final Activity activity) { + public static void transparentStatusBar(@NonNull final Activity activity) { transparentStatusBar(activity.getWindow()); } - public static void transparentStatusBar(final Window window) { + public static void transparentStatusBar(@NonNull final Window window) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); @@ -431,7 +433,7 @@ public static int getActionBarHeight() { TypedValue tv = new TypedValue(); if (Utils.getApp().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { return TypedValue.complexToDimensionPixelSize( - tv.data, Resources.getSystem().getDisplayMetrics() + tv.data, Utils.getApp().getResources().getDisplayMetrics() ); } return 0; @@ -515,7 +517,7 @@ public static void setNavBarVisibility(@NonNull final Window window, boolean isV final View child = decorView.getChildAt(i); final int id = child.getId(); if (id != View.NO_ID) { - String resourceEntryName = Resources.getSystem().getResourceEntryName(id); + String resourceEntryName = getResNameById(id); if ("navigationBarBackground".equals(resourceEntryName)) { child.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE); } @@ -556,7 +558,7 @@ public static boolean isNavBarVisible(@NonNull final Window window) { final View child = decorView.getChildAt(i); final int id = child.getId(); if (id != View.NO_ID) { - String resourceEntryName = Resources.getSystem().getResourceEntryName(id); + String resourceEntryName = getResNameById(id); if ("navigationBarBackground".equals(resourceEntryName) && child.getVisibility() == View.VISIBLE) { isVisible = true; @@ -565,12 +567,33 @@ public static boolean isNavBarVisible(@NonNull final Window window) { } } if (isVisible) { + // 对于三星手机,android10以下非OneUI2的版本,比如 s8,note8 等设备上, + // 导航栏显示存在bug:"当用户隐藏导航栏时显示输入法的时候导航栏会跟随显示",会导致隐藏输入法之后判断错误 + // 这个问题在 OneUI 2 & android 10 版本已修复 + if (UtilsBridge.isSamsung() + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 + && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + try { + return Settings.Global.getInt(Utils.getApp().getContentResolver(), "navigationbar_hide_bar_enabled") == 0; + } catch (Exception ignore) { + } + } + int visibility = decorView.getSystemUiVisibility(); isVisible = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; } + return isVisible; } + private static String getResNameById(int id) { + try { + return Utils.getApp().getResources().getResourceEntryName(id); + } catch (Exception ignore) { + return ""; + } + } + /** * Set the navigation bar's color. * @@ -692,4 +715,26 @@ public static boolean isNavBarLightMode(@NonNull final Window window) { } return false; } + + public static void transparentNavBar(@NonNull final Activity activity) { + transparentNavBar(activity.getWindow()); + } + + public static void transparentNavBar(@NonNull final Window window) { + if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + window.setNavigationBarContrastEnforced(false); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.setNavigationBarColor(Color.TRANSPARENT); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if ((window.getAttributes().flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0) { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + } + } + View decorView = window.getDecorView(); + int vis = decorView.getSystemUiVisibility(); + int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; + decorView.setSystemUiVisibility(vis | option); + } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java index f9344b0a59..08dd46ff9b 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java @@ -2,11 +2,12 @@ import android.content.ContentResolver; import android.provider.Settings; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; import android.view.Window; import android.view.WindowManager; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; + /** ** author: Blankj @@ -105,7 +106,7 @@ public static void setWindowBrightness(@NonNull final Window window, * @param window 窗口 * @return 屏幕亮度 0-255 */ - public static int getWindowBrightness(final Window window) { + public static int getWindowBrightness(@NonNull final Window window) { WindowManager.LayoutParams lp = window.getAttributes(); float brightness = lp.screenBrightness; if (brightness < 0) return getBrightness(); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/BusUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/BusUtils.java index 811470c648..537a55fd92 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/BusUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/BusUtils.java @@ -8,8 +8,6 @@ import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -18,6 +16,9 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** ** author: Blankj @@ -31,8 +32,7 @@ public final class BusUtils { private static final Object NULL = "nULl"; private static final String TAG = "BusUtils"; - private final Map> mTag_BusInfoListMap = new HashMap<>(); - + private final Map > mTag_BusInfoListMap = new ConcurrentHashMap<>(); private final Map > mClassName_BusesMap = new ConcurrentHashMap<>(); private final Map > mClassName_TagsMap = new ConcurrentHashMap<>(); private final Map > mClassName_Tag_Arg4StickyMap = new ConcurrentHashMap<>(); @@ -58,33 +58,33 @@ private void registerBus(String tag, boolean sticky, String threadMode, int priority) { List busInfoList = mTag_BusInfoListMap.get(tag); if (busInfoList == null) { - busInfoList = new ArrayList<>(); + busInfoList = new CopyOnWriteArrayList<>(); mTag_BusInfoListMap.put(tag, busInfoList); } - busInfoList.add(new BusInfo(className, funName, paramType, paramName, sticky, threadMode, priority)); + busInfoList.add(new BusInfo(tag, className, funName, paramType, paramName, sticky, threadMode, priority)); } - public static void register(final Object bus) { + public static void register(@Nullable final Object bus) { getInstance().registerInner(bus); } - public static void unregister(final Object bus) { + public static void unregister(@Nullable final Object bus) { getInstance().unregisterInner(bus); } - public static void post(final String tag) { + public static void post(@NonNull final String tag) { post(tag, NULL); } - public static void post(final String tag, final Object arg) { + public static void post(@NonNull final String tag, @NonNull final Object arg) { getInstance().postInner(tag, arg); } - public static void postSticky(final String tag) { + public static void postSticky(@NonNull final String tag) { postSticky(tag, NULL); } - public static void postSticky(final String tag, final Object arg) { + public static void postSticky(@NonNull final String tag, final Object arg) { getInstance().postStickyInner(tag, arg); } @@ -105,18 +105,32 @@ private static BusUtils getInstance() { return LazyHolder.INSTANCE; } - private void registerInner(final Object bus) { + private void registerInner(@Nullable final Object bus) { if (bus == null) return; - Class aClass = bus.getClass(); + Class> aClass = bus.getClass(); String className = aClass.getName(); + boolean isNeedRecordTags = false; synchronized (mClassName_BusesMap) { Set buses = mClassName_BusesMap.get(className); if (buses == null) { buses = new CopyOnWriteArraySet<>(); mClassName_BusesMap.put(className, buses); + isNeedRecordTags = true; } - buses.add(bus); + if (buses.contains(bus)) { + Log.w(TAG, "The bus of <" + bus + "> already registered."); + return; + } else { + buses.add(bus); + } + } + if (isNeedRecordTags) { + recordTags(aClass, className); } + consumeStickyIfExist(bus); + } + + private void recordTags(Class> aClass, String className) { List tags = mClassName_TagsMap.get(className); if (tags == null) { synchronized (mClassName_TagsMap) { @@ -139,15 +153,38 @@ private void registerInner(final Object bus) { } } } - processSticky(bus); } - private void processSticky(final Object bus) { + private void consumeStickyIfExist(final Object bus) { Map tagArgMap = mClassName_Tag_Arg4StickyMap.get(bus.getClass().getName()); if (tagArgMap == null) return; synchronized (mClassName_Tag_Arg4StickyMap) { for (Map.Entry tagArgEntry : tagArgMap.entrySet()) { - postInner(tagArgEntry.getKey(), tagArgEntry.getValue()); + consumeSticky(bus, tagArgEntry.getKey(), tagArgEntry.getValue()); + } + } + } + + private void consumeSticky(final Object bus, final String tag, final Object arg) { + List busInfoList = mTag_BusInfoListMap.get(tag); + if (busInfoList == null) { + Log.e(TAG, "The bus of tag <" + tag + "> is not exists."); + return; + } + for (BusInfo busInfo : busInfoList) { + if (!busInfo.subClassNames.contains(bus.getClass().getName())) { + continue; + } + if (!busInfo.sticky) { + continue; + } + + synchronized (mClassName_Tag_Arg4StickyMap) { + Map tagArgMap = mClassName_Tag_Arg4StickyMap.get(busInfo.className); + if (tagArgMap == null || !tagArgMap.containsKey(tag)) { + continue; + } + invokeBus(bus, arg, busInfo, true); } } } @@ -173,18 +210,29 @@ private void postInner(final String tag, final Object arg, final boolean sticky) List busInfoList = mTag_BusInfoListMap.get(tag); if (busInfoList == null) { Log.e(TAG, "The bus of tag <" + tag + "> is not exists."); + if (mTag_BusInfoListMap.isEmpty()) { + Log.e(TAG, "Please check whether the bus plugin is applied."); + } return; } for (BusInfo busInfo : busInfoList) { - if (busInfo.method == null) { - Method method = getMethodByBusInfo(busInfo); - if (method == null) { - return; - } - busInfo.method = method; + invokeBus(arg, busInfo, sticky); + } + } + + private void invokeBus(Object arg, BusInfo busInfo, boolean sticky) { + invokeBus(null, arg, busInfo, sticky); + } + + private void invokeBus(Object bus, Object arg, BusInfo busInfo, boolean sticky) { + if (busInfo.method == null) { + Method method = getMethodByBusInfo(busInfo); + if (method == null) { + return; } - invokeMethod(tag, arg, busInfo, sticky); + busInfo.method = method; } + invokeMethod(bus, arg, busInfo, sticky); } private Method getMethodByBusInfo(BusInfo busInfo) { @@ -225,11 +273,15 @@ private Class getClassName(String paramType) throws ClassNotFoundException { } } - private void invokeMethod(final String tag, final Object arg, final BusInfo busInfo, final boolean sticky) { + private void invokeMethod(final Object arg, final BusInfo busInfo, final boolean sticky) { + invokeMethod(null, arg, busInfo, sticky); + } + + private void invokeMethod(final Object bus, final Object arg, final BusInfo busInfo, final boolean sticky) { Runnable runnable = new Runnable() { @Override public void run() { - realInvokeMethod(tag, arg, busInfo, sticky); + realInvokeMethod(bus, arg, busInfo, sticky); } }; switch (busInfo.threadMode) { @@ -253,22 +305,28 @@ public void run() { } } - private void realInvokeMethod(final String tag, Object arg, BusInfo busInfo, boolean sticky) { + private void realInvokeMethod(Object bus, Object arg, BusInfo busInfo, boolean sticky) { Set buses = new HashSet<>(); - for (String subClassName : busInfo.subClassNames) { - Set subBuses = mClassName_BusesMap.get(subClassName); - if (subBuses != null && !subBuses.isEmpty()) { - buses.addAll(subBuses); + if (bus == null) { + for (String subClassName : busInfo.subClassNames) { + Set subBuses = mClassName_BusesMap.get(subClassName); + if (subBuses != null && !subBuses.isEmpty()) { + buses.addAll(subBuses); + } } - } - if (buses.size() == 0) { - if (!sticky) { - Log.e(TAG, "The bus of tag <" + tag + "> was not registered before."); - return; - } else { + if (buses.size() == 0) { + if (!sticky) { + Log.e(TAG, "The " + busInfo + " was not registered before."); + } return; } + } else { + buses.add(bus); } + invokeBuses(arg, busInfo, buses); + } + + private void invokeBuses(Object arg, BusInfo busInfo, Set buses) { try { if (arg == NULL) { for (Object bus : buses) { @@ -292,20 +350,21 @@ private void postStickyInner(final String tag, final Object arg) { Log.e(TAG, "The bus of tag <" + tag + "> is not exists."); return; } + // 获取多对象,然后消费各个 busInfoList for (BusInfo busInfo : busInfoList) { if (!busInfo.sticky) { // not sticky bus will post directly. - postInner(tag, arg); - return; + invokeBus(arg, busInfo, false); + continue; } synchronized (mClassName_Tag_Arg4StickyMap) { Map tagArgMap = mClassName_Tag_Arg4StickyMap.get(busInfo.className); if (tagArgMap == null) { - tagArgMap = new HashMap<>(); + tagArgMap = new ConcurrentHashMap<>(); mClassName_Tag_Arg4StickyMap.put(busInfo.className, tagArgMap); } tagArgMap.put(tag, arg); } - postInner(tag, arg, true); + invokeBus(arg, busInfo, true); } } @@ -317,13 +376,11 @@ private void removeStickyInner(final String tag) { } for (BusInfo busInfo : busInfoList) { if (!busInfo.sticky) { - Log.e(TAG, "The bus of tag <" + tag + "> is not sticky."); - return; + continue; } synchronized (mClassName_Tag_Arg4StickyMap) { Map tagArgMap = mClassName_Tag_Arg4StickyMap.get(busInfo.className); if (tagArgMap == null || !tagArgMap.containsKey(tag)) { - Log.e(TAG, "The sticky bus of tag <" + tag + "> didn't post."); return; } tagArgMap.remove(tag); @@ -339,6 +396,7 @@ static void registerBus4Test(String tag, private static final class BusInfo { + String tag; String className; String funName; String paramType; @@ -349,8 +407,9 @@ private static final class BusInfo { Method method; List subClassNames; - BusInfo(String className, String funName, String paramType, String paramName, + BusInfo(String tag, String className, String funName, String paramType, String paramName, boolean sticky, String threadMode, int priority) { + this.tag = tag; this.className = className; this.funName = funName; this.paramType = paramType; @@ -363,14 +422,19 @@ private static final class BusInfo { @Override public String toString() { - return "BusInfo { desc: " + className + "#" + funName + - ("".equals(paramType) ? "()" : ("(" + paramType + " " + paramName + ")")) + + return "BusInfo { tag : " + tag + + ", desc: " + getDesc() + ", sticky: " + sticky + ", threadMode: " + threadMode + ", method: " + method + ", priority: " + priority + " }"; } + + private String getDesc() { + return className + "#" + funName + + ("".equals(paramType) ? "()" : ("(" + paramType + " " + paramName + ")")); + } } public enum ThreadMode { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java index bb48a4b5cf..23100f60b0 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java @@ -3,13 +3,15 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Parcelable; -import android.support.annotation.NonNull; import org.json.JSONArray; import org.json.JSONObject; import java.io.Serializable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** * * author: Blankj @@ -27,7 +29,7 @@ public final class CacheDiskStaticUtils { * * @param cacheDiskUtils The default instance of {@link CacheDiskUtils}. */ - public static void setDefaultCacheDiskUtils(final CacheDiskUtils cacheDiskUtils) { + public static void setDefaultCacheDiskUtils(@Nullable final CacheDiskUtils cacheDiskUtils) { sDefaultCacheDiskUtils = cacheDiskUtils; } @@ -37,7 +39,7 @@ public static void setDefaultCacheDiskUtils(final CacheDiskUtils cacheDiskUtils) * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final byte[] value) { + public static void put(@NonNull final String key, @Nullable final byte[] value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -48,7 +50,7 @@ public static void put(@NonNull final String key, final byte[] value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final byte[] value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final byte[] value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -69,7 +71,7 @@ public static byte[] getBytes(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the bytes if cache exists or defaultValue otherwise */ - public static byte[] getBytes(@NonNull final String key, final byte[] defaultValue) { + public static byte[] getBytes(@NonNull final String key, @Nullable final byte[] defaultValue) { return getBytes(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -83,7 +85,7 @@ public static byte[] getBytes(@NonNull final String key, final byte[] defaultVal * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final String value) { + public static void put(@NonNull final String key, @Nullable final String value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -94,7 +96,7 @@ public static void put(@NonNull final String key, final String value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final String value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final String value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -115,7 +117,7 @@ public static String getString(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the string value if cache exists or defaultValue otherwise */ - public static String getString(@NonNull final String key, final String defaultValue) { + public static String getString(@NonNull final String key, @Nullable final String defaultValue) { return getString(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -129,7 +131,7 @@ public static String getString(@NonNull final String key, final String defaultVa * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final JSONObject value) { + public static void put(@NonNull final String key, @Nullable final JSONObject value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -141,7 +143,7 @@ public static void put(@NonNull final String key, final JSONObject value) { * @param saveTime The save time of cache, in seconds. */ public static void put(@NonNull final String key, - final JSONObject value, + @Nullable final JSONObject value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -163,7 +165,7 @@ public static JSONObject getJSONObject(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the JSONObject if cache exists or defaultValue otherwise */ - public static JSONObject getJSONObject(@NonNull final String key, final JSONObject defaultValue) { + public static JSONObject getJSONObject(@NonNull final String key, @Nullable final JSONObject defaultValue) { return getJSONObject(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -178,7 +180,7 @@ public static JSONObject getJSONObject(@NonNull final String key, final JSONObje * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final JSONArray value) { + public static void put(@NonNull final String key, @Nullable final JSONArray value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -189,7 +191,7 @@ public static void put(@NonNull final String key, final JSONArray value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final JSONArray value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final JSONArray value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -210,7 +212,7 @@ public static JSONArray getJSONArray(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the JSONArray if cache exists or defaultValue otherwise */ - public static JSONArray getJSONArray(@NonNull final String key, final JSONArray defaultValue) { + public static JSONArray getJSONArray(@NonNull final String key, @Nullable final JSONArray defaultValue) { return getJSONArray(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -225,7 +227,7 @@ public static JSONArray getJSONArray(@NonNull final String key, final JSONArray * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final Bitmap value) { + public static void put(@NonNull final String key, @Nullable final Bitmap value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -236,7 +238,7 @@ public static void put(@NonNull final String key, final Bitmap value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final Bitmap value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final Bitmap value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -257,7 +259,7 @@ public static Bitmap getBitmap(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the bitmap if cache exists or defaultValue otherwise */ - public static Bitmap getBitmap(@NonNull final String key, final Bitmap defaultValue) { + public static Bitmap getBitmap(@NonNull final String key, @Nullable final Bitmap defaultValue) { return getBitmap(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -271,7 +273,7 @@ public static Bitmap getBitmap(@NonNull final String key, final Bitmap defaultVa * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final Drawable value) { + public static void put(@NonNull final String key, @Nullable final Drawable value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -282,7 +284,7 @@ public static void put(@NonNull final String key, final Drawable value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final Drawable value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final Drawable value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -303,7 +305,7 @@ public static Drawable getDrawable(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the drawable if cache exists or defaultValue otherwise */ - public static Drawable getDrawable(@NonNull final String key, final Drawable defaultValue) { + public static Drawable getDrawable(@NonNull final String key, final @Nullable Drawable defaultValue) { return getDrawable(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -317,7 +319,7 @@ public static Drawable getDrawable(@NonNull final String key, final Drawable def * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final Parcelable value) { + public static void put(@NonNull final String key, @Nullable final Parcelable value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -328,7 +330,7 @@ public static void put(@NonNull final String key, final Parcelable value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final Parcelable value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final Parcelable value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -356,7 +358,7 @@ public staticT getParcelable(@NonNull final String key, */ public static T getParcelable(@NonNull final String key, @NonNull final Parcelable.Creator creator, - final T defaultValue) { + @Nullable final T defaultValue) { return getParcelable(key, creator, defaultValue, getDefaultCacheDiskUtils()); } @@ -370,7 +372,7 @@ public static T getParcelable(@NonNull final String key, * @param key The key of cache. * @param value The value of cache. */ - public static void put(@NonNull final String key, final Serializable value) { + public static void put(@NonNull final String key, @Nullable final Serializable value) { put(key, value, getDefaultCacheDiskUtils()); } @@ -381,7 +383,7 @@ public static void put(@NonNull final String key, final Serializable value) { * @param value The value of cache. * @param saveTime The save time of cache, in seconds. */ - public static void put(@NonNull final String key, final Serializable value, final int saveTime) { + public static void put(@NonNull final String key, @Nullable final Serializable value, final int saveTime) { put(key, value, saveTime, getDefaultCacheDiskUtils()); } @@ -402,7 +404,7 @@ public static Object getSerializable(@NonNull final String key) { * @param defaultValue The default value if the cache doesn't exist. * @return the bitmap if cache exists or defaultValue otherwise */ - public static Object getSerializable(@NonNull final String key, final Object defaultValue) { + public static Object getSerializable(@NonNull final String key, @Nullable final Object defaultValue) { return getSerializable(key, defaultValue, getDefaultCacheDiskUtils()); } @@ -455,7 +457,7 @@ public static boolean clear() { * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final byte[] value, + @Nullable final byte[] value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -469,7 +471,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final byte[] value, + @Nullable final byte[] value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -495,7 +497,7 @@ public static byte[] getBytes(@NonNull final String key, @NonNull final CacheDis * @return the bytes if cache exists or defaultValue otherwise */ public static byte[] getBytes(@NonNull final String key, - final byte[] defaultValue, + @Nullable final byte[] defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getBytes(key, defaultValue); } @@ -512,7 +514,7 @@ public static byte[] getBytes(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final String value, + @Nullable final String value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -526,7 +528,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final String value, + @Nullable final String value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -552,7 +554,7 @@ public static String getString(@NonNull final String key, @NonNull final CacheDi * @return the string value if cache exists or defaultValue otherwise */ public static String getString(@NonNull final String key, - final String defaultValue, + @Nullable final String defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getString(key, defaultValue); } @@ -569,7 +571,7 @@ public static String getString(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final JSONObject value, + @Nullable final JSONObject value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -583,7 +585,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final JSONObject value, + @Nullable final JSONObject value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -609,7 +611,7 @@ public static JSONObject getJSONObject(@NonNull final String key, @NonNull final * @return the JSONObject if cache exists or defaultValue otherwise */ public static JSONObject getJSONObject(@NonNull final String key, - final JSONObject defaultValue, + @Nullable final JSONObject defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getJSONObject(key, defaultValue); } @@ -627,7 +629,7 @@ public static JSONObject getJSONObject(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final JSONArray value, + @Nullable final JSONArray value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -641,7 +643,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final JSONArray value, + @Nullable final JSONArray value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -667,7 +669,7 @@ public static JSONArray getJSONArray(@NonNull final String key, @NonNull final C * @return the JSONArray if cache exists or defaultValue otherwise */ public static JSONArray getJSONArray(@NonNull final String key, - final JSONArray defaultValue, + @Nullable final JSONArray defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getJSONArray(key, defaultValue); } @@ -685,7 +687,7 @@ public static JSONArray getJSONArray(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Bitmap value, + @Nullable final Bitmap value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -699,7 +701,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Bitmap value, + @Nullable final Bitmap value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -725,7 +727,7 @@ public static Bitmap getBitmap(@NonNull final String key, @NonNull final CacheDi * @return the bitmap if cache exists or defaultValue otherwise */ public static Bitmap getBitmap(@NonNull final String key, - final Bitmap defaultValue, + @Nullable final Bitmap defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getBitmap(key, defaultValue); } @@ -742,7 +744,7 @@ public static Bitmap getBitmap(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Drawable value, + @Nullable final Drawable value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -756,7 +758,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Drawable value, + @Nullable final Drawable value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -782,7 +784,7 @@ public static Drawable getDrawable(@NonNull final String key, @NonNull final Cac * @return the drawable if cache exists or defaultValue otherwise */ public static Drawable getDrawable(@NonNull final String key, - final Drawable defaultValue, + @Nullable final Drawable defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getDrawable(key, defaultValue); } @@ -799,7 +801,7 @@ public static Drawable getDrawable(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Parcelable value, + @Nullable final Parcelable value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -813,7 +815,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Parcelable value, + @Nullable final Parcelable value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -846,7 +848,7 @@ public static T getParcelable(@NonNull final String key, */ public static T getParcelable(@NonNull final String key, @NonNull final Parcelable.Creator creator, - final T defaultValue, + @Nullable final T defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getParcelable(key, creator, defaultValue); } @@ -863,7 +865,7 @@ public static T getParcelable(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Serializable value, + @Nullable final Serializable value, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value); } @@ -877,7 +879,7 @@ public static void put(@NonNull final String key, * @param cacheDiskUtils The instance of {@link CacheDiskUtils}. */ public static void put(@NonNull final String key, - final Serializable value, + @Nullable final Serializable value, final int saveTime, @NonNull final CacheDiskUtils cacheDiskUtils) { cacheDiskUtils.put(key, value, saveTime); @@ -903,7 +905,7 @@ public static Object getSerializable(@NonNull final String key, @NonNull final C * @return the bitmap if cache exists or defaultValue otherwise */ public static Object getSerializable(@NonNull final String key, - final Object defaultValue, + @Nullable final Object defaultValue, @NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.getSerializable(key, defaultValue); } @@ -949,6 +951,7 @@ public static boolean clear(@NonNull final CacheDiskUtils cacheDiskUtils) { return cacheDiskUtils.clear(); } + @NonNull private static CacheDiskUtils getDefaultCacheDiskUtils() { return sDefaultCacheDiskUtils != null ? sDefaultCacheDiskUtils : CacheDiskUtils.getInstance(); } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java index 1c316c6a32..773e550a16 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java @@ -3,9 +3,10 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Parcelable; -import android.support.annotation.NonNull; import android.util.Log; +import androidx.annotation.NonNull; + import com.blankj.utilcode.constant.CacheConstants; import org.json.JSONArray; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java index 2ef267bd01..6dbb9f7475 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java @@ -3,13 +3,14 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Parcelable; -import android.support.annotation.NonNull; import org.json.JSONArray; import org.json.JSONObject; import java.io.Serializable; +import androidx.annotation.NonNull; + /** * * author: Blankj diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java index c800423c78..c39c9ef9d4 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java @@ -3,7 +3,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Parcelable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.blankj.utilcode.constant.CacheConstants; @@ -113,7 +113,12 @@ public byte[] getBytes(@NonNull final String key) { public byte[] getBytes(@NonNull final String key, final byte[] defaultValue) { byte[] obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getBytes(key, defaultValue); + byte[] bytes = mCacheDiskUtils.getBytes(key); + if (bytes != null) { + mCacheMemoryUtils.put(key, bytes); + return bytes; + } + return defaultValue; } /////////////////////////////////////////////////////////////////////////// @@ -162,7 +167,12 @@ public String getString(@NonNull final String key) { public String getString(@NonNull final String key, final String defaultValue) { String obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getString(key, defaultValue); + String string = mCacheDiskUtils.getString(key); + if (string != null) { + mCacheMemoryUtils.put(key, string); + return string; + } + return defaultValue; } /////////////////////////////////////////////////////////////////////////// @@ -213,7 +223,12 @@ public JSONObject getJSONObject(@NonNull final String key) { public JSONObject getJSONObject(@NonNull final String key, final JSONObject defaultValue) { JSONObject obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getJSONObject(key, defaultValue); + JSONObject jsonObject = mCacheDiskUtils.getJSONObject(key); + if (jsonObject != null) { + mCacheMemoryUtils.put(key, jsonObject); + return jsonObject; + } + return defaultValue; } @@ -263,7 +278,12 @@ public JSONArray getJSONArray(@NonNull final String key) { public JSONArray getJSONArray(@NonNull final String key, final JSONArray defaultValue) { JSONArray obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getJSONArray(key, defaultValue); + JSONArray jsonArray = mCacheDiskUtils.getJSONArray(key); + if (jsonArray != null) { + mCacheMemoryUtils.put(key, jsonArray); + return jsonArray; + } + return defaultValue; } /////////////////////////////////////////////////////////////////////////// @@ -312,7 +332,12 @@ public Bitmap getBitmap(@NonNull final String key) { public Bitmap getBitmap(@NonNull final String key, final Bitmap defaultValue) { Bitmap obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getBitmap(key, defaultValue); + Bitmap bitmap = mCacheDiskUtils.getBitmap(key); + if (bitmap != null) { + mCacheMemoryUtils.put(key, bitmap); + return bitmap; + } + return defaultValue; } /////////////////////////////////////////////////////////////////////////// @@ -361,7 +386,12 @@ public Drawable getDrawable(@NonNull final String key) { public Drawable getDrawable(@NonNull final String key, final Drawable defaultValue) { Drawable obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getDrawable(key, defaultValue); + Drawable drawable = mCacheDiskUtils.getDrawable(key); + if (drawable != null) { + mCacheMemoryUtils.put(key, drawable); + return drawable; + } + return defaultValue; } /////////////////////////////////////////////////////////////////////////// @@ -417,7 +447,12 @@ publicT getParcelable(@NonNull final String key, final T defaultValue) { T value = mCacheMemoryUtils.get(key); if (value != null) return value; - return mCacheDiskUtils.getParcelable(key, creator, defaultValue); + T val = mCacheDiskUtils.getParcelable(key, creator); + if (val != null) { + mCacheMemoryUtils.put(key, val); + return val; + } + return defaultValue; } /////////////////////////////////////////////////////////////////////////// @@ -466,7 +501,12 @@ public Object getSerializable(@NonNull final String key) { public Object getSerializable(@NonNull final String key, final Object defaultValue) { Object obj = mCacheMemoryUtils.get(key); if (obj != null) return obj; - return mCacheDiskUtils.getSerializable(key, defaultValue); + Object serializable = mCacheDiskUtils.getSerializable(key); + if (serializable != null) { + mCacheMemoryUtils.put(key, serializable); + return serializable; + } + return defaultValue; } /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java index 56abfba117..aedcfa7fc4 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java @@ -1,6 +1,6 @@ package com.blankj.utilcode.util; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java index d0e06e394d..ddaa2baed9 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java @@ -1,7 +1,7 @@ package com.blankj.utilcode.util; -import android.support.annotation.NonNull; -import android.support.v4.util.LruCache; +import androidx.annotation.NonNull; +import androidx.collection.LruCache; import com.blankj.utilcode.constant.CacheConstants; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CleanUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CleanUtils.java index aa95ae7126..7db3edbd6a 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CleanUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CleanUtils.java @@ -1,9 +1,14 @@ package com.blankj.utilcode.util; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; import android.os.Environment; import java.io.File; +import androidx.annotation.RequiresApi; + /** ** author: Blankj @@ -89,4 +94,11 @@ public static boolean cleanExternalCache() { public static boolean cleanCustomDir(final String dirPath) { return UtilsBridge.deleteAllInDir(UtilsBridge.getFileByPath(dirPath)); } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + public static void cleanAppUserData() { + ActivityManager am = (ActivityManager) Utils.getApp().getSystemService(Context.ACTIVITY_SERVICE); + //noinspection ConstantConditions + am.clearApplicationUserData(); + } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClickUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClickUtils.java index 6fd8f11963..8f73792f8f 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClickUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClickUtils.java @@ -13,15 +13,17 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.os.Build; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.v4.view.ViewCompat; +import android.os.SystemClock; import android.util.Log; import android.util.StateSet; import android.view.MotionEvent; import android.view.TouchDelegate; import android.view.View; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; + /** ** author: Blankj @@ -45,8 +47,7 @@ public class ClickUtils { private static final int PRESSED_BG_DARK_STYLE = 5; private static final float PRESSED_BG_DARK_DEFAULT_VALUE = 0.9f; - private static final int DEBOUNCING_TAG = -7; - private static final long DEBOUNCING_DEFAULT_VALUE = 200; + private static final long DEBOUNCING_DEFAULT_VALUE = 1000; private ClickUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); @@ -213,23 +214,15 @@ private static Drawable createStyleDrawable(Drawable src, int style, float value } private static Drawable createAlphaDrawable(Drawable drawable, float alpha) { -// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - DrawableWrapperBefore21 drawableWrapper = new DrawableWrapperBefore21(drawable); - drawableWrapper.setAlphaFix((int) (alpha * 255)); - return drawableWrapper; -// } -// drawable.setAlpha((int) (alpha * 255)); -// return drawable; + ClickDrawableWrapper drawableWrapper = new ClickDrawableWrapper(drawable); + drawableWrapper.setAlpha((int) (alpha * 255)); + return drawableWrapper; } private static Drawable createDarkDrawable(Drawable drawable, float alpha) { -// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - DrawableWrapperBefore21 drawableWrapper = new DrawableWrapperBefore21(drawable); - drawableWrapper.setColorFilterFix(getDarkColorFilter(alpha)); - return drawableWrapper; -// } -// drawable.setColorFilter(getDarkColorFilter(alpha)); -// return drawable; + ClickDrawableWrapper drawableWrapper = new ClickDrawableWrapper(drawable); + drawableWrapper.setColorFilter(getDarkColorFilter(alpha)); + return drawableWrapper; } private static ColorMatrixColorFilter getDarkColorFilter(float darkAlpha) { @@ -393,8 +386,8 @@ public static void back2HomeFriendly(final CharSequence tip) { public static void back2HomeFriendly(@NonNull final CharSequence tip, final long duration, @NonNull Back2HomeFriendlyListener listener) { - long nowMillis = System.currentTimeMillis(); - if (nowMillis - sLastClickMillis < duration) { + long nowMillis = SystemClock.elapsedRealtime(); + if (Math.abs(nowMillis - sLastClickMillis) < duration) { sClickCount++; if (sClickCount == 2) { UtilsBridge.startHomeActivity(); @@ -438,21 +431,7 @@ public void run() { }; private static boolean isValid(@NonNull final View view, final long duration) { - long curTime = System.currentTimeMillis(); - Object tag = view.getTag(DEBOUNCING_TAG); - if (!(tag instanceof Long)) { - view.setTag(DEBOUNCING_TAG, curTime); - return true; - } - long preTime = (Long) tag; - if (curTime - preTime < 0) { - view.setTag(DEBOUNCING_TAG, curTime); - return false; - } else if (curTime - preTime <= duration) { - return false; - } - view.setTag(DEBOUNCING_TAG, curTime); - return true; + return UtilsBridge.isValid(view, duration); } private long mDuration; @@ -586,14 +565,14 @@ private static class LazyHolder { } } - static class DrawableWrapperBefore21 extends ShadowUtils.DrawableWrapper { + static class ClickDrawableWrapper extends ShadowUtils.DrawableWrapper { private BitmapDrawable mBitmapDrawable = null; - //低版本ColorDrawable.setColorFilter无效,这里直接用画笔画上 + // 低版本ColorDrawable.setColorFilter无效,这里直接用画笔画上 private Paint mColorPaint = null; - public DrawableWrapperBefore21(Drawable drawable) { + public ClickDrawableWrapper(Drawable drawable) { super(drawable); if (drawable instanceof ColorDrawable) { mColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); @@ -603,25 +582,23 @@ public DrawableWrapperBefore21(Drawable drawable) { @Override public void setColorFilter(ColorFilter cf) { - //低版本StateListDrawable.selectDrawable会重置ColorFilter - } - - public void setColorFilterFix(ColorFilter cf) { super.setColorFilter(cf); - if (mColorPaint != null) { - mColorPaint.setColorFilter(cf); + // 低版本 StateListDrawable.selectDrawable 会重置 ColorFilter + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + if (mColorPaint != null) { + mColorPaint.setColorFilter(cf); + } } } @Override public void setAlpha(int alpha) { - //低版本StateListDrawable.selectDrawable会重置Alpha - } - - public void setAlphaFix(int alpha) { super.setAlpha(alpha); - if (mColorPaint != null) { - mColorPaint.setColor(((ColorDrawable) getWrappedDrawable()).getColor()); + // 低版本 StateListDrawable.selectDrawable 会重置 Alpha + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + if (mColorPaint != null) { + mColorPaint.setColor(((ColorDrawable) getWrappedDrawable()).getColor()); + } } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClipboardUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClipboardUtils.java new file mode 100644 index 0000000000..82127b4847 --- /dev/null +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClipboardUtils.java @@ -0,0 +1,109 @@ +package com.blankj.utilcode.util; + +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.ClipboardManager; +import android.content.Context; + +/** + *+ * author: Blankj + * blog : http://blankj.com + * time : 2016/09/25 + * desc : utils about clipboard + *+ */ +public final class ClipboardUtils { + + private ClipboardUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Copy the text to clipboard. + *The label equals name of package.
+ * + * @param text The text. + */ + public static void copyText(final CharSequence text) { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + cm.setPrimaryClip(ClipData.newPlainText(Utils.getApp().getPackageName(), text)); + } + + /** + * Copy the text to clipboard. + * + * @param label The label. + * @param text The text. + */ + public static void copyText(final CharSequence label, final CharSequence text) { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + cm.setPrimaryClip(ClipData.newPlainText(label, text)); + } + + /** + * Clear the clipboard. + */ + public static void clear() { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + cm.setPrimaryClip(ClipData.newPlainText(null, "")); + } + + /** + * Return the label for clipboard. + * + * @return the label for clipboard + */ + public static CharSequence getLabel() { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + ClipDescription des = cm.getPrimaryClipDescription(); + if (des == null) { + return ""; + } + CharSequence label = des.getLabel(); + if (label == null) { + return ""; + } + return label; + } + + /** + * Return the text for clipboard. + * + * @return the text for clipboard + */ + public static CharSequence getText() { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + ClipData clip = cm.getPrimaryClip(); + if (clip != null && clip.getItemCount() > 0) { + CharSequence text = clip.getItemAt(0).coerceToText(Utils.getApp()); + if (text != null) { + return text; + } + } + return ""; + } + + /** + * Add the clipboard changed listener. + */ + public static void addChangedListener(final ClipboardManager.OnPrimaryClipChangedListener listener) { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + cm.addPrimaryClipChangedListener(listener); + } + + /** + * Remove the clipboard changed listener. + */ + public static void removeChangedListener(final ClipboardManager.OnPrimaryClipChangedListener listener) { + ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); + //noinspection ConstantConditions + cm.removePrimaryClipChangedListener(listener); + } +} diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CollectionUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CollectionUtils.java index 31517d741d..2fcdbd18ed 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CollectionUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CollectionUtils.java @@ -79,7 +79,7 @@ public staticArrayList newArrayListNotNull(E... array) { } @SafeVarargs - public static List newLinkedList(E... array) { + public static LinkedList newLinkedList(E... array) { LinkedList list = new LinkedList<>(); if (array == null || array.length == 0) return list; for (E e : array) { @@ -89,7 +89,7 @@ public static List newLinkedList(E... array) { } @SafeVarargs - public static List newLinkedListNotNull(E... array) { + public static LinkedList newLinkedListNotNull(E... array) { LinkedList list = new LinkedList<>(); if (array == null || array.length == 0) return list; for (E e : array) { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ColorUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ColorUtils.java index 93763b470b..c75e866124 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ColorUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ColorUtils.java @@ -1,12 +1,12 @@ package com.blankj.utilcode.util; import android.graphics.Color; -import android.support.annotation.ColorInt; -import android.support.annotation.ColorRes; -import android.support.annotation.FloatRange; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.annotation.FloatRange; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; /** * @@ -204,4 +204,14 @@ public static int getRandomColor(final boolean supportAlpha) { int high = supportAlpha ? (int) (Math.random() * 0x100) << 24 : 0xFF000000; return high | (int) (Math.random() * 0x1000000); } + + /** + * Return whether the color is light. + * + * @param color The color. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isLightColor(@ColorInt int color) { + return 0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color) >= 127.5; + } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ConvertUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ConvertUtils.java index 26e59fd330..d6f9eaafaf 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ConvertUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ConvertUtils.java @@ -566,7 +566,7 @@ public static ByteArrayOutputStream input2OutputStream(final InputStream is) { /** * Output stream to input stream. */ - public ByteArrayInputStream output2InputStream(final OutputStream out) { + public static ByteArrayInputStream output2InputStream(final OutputStream out) { if (out == null) return null; return new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()); } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CrashUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CrashUtils.java index dd049e7e77..598f7fdbac 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/CrashUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CrashUtils.java @@ -1,13 +1,11 @@ package com.blankj.utilcode.util; -import android.annotation.SuppressLint; -import android.os.Build; -import android.support.annotation.NonNull; - +import androidx.annotation.NonNull; import java.io.File; import java.lang.Thread.UncaughtExceptionHandler; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Map; /** *@@ -21,7 +19,8 @@ public final class CrashUtils { private static final String FILE_SEP = System.getProperty("file.separator"); - private static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); + private static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = + Thread.getDefaultUncaughtExceptionHandler(); private CrashUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); @@ -30,7 +29,6 @@ private CrashUtils() { /** * Initialization. */ - @SuppressLint("MissingPermission") public static void init() { init(""); } @@ -65,7 +63,7 @@ public static void init(final OnCrashListener onCrashListener) { /** * Initialization * - * @param crashDir The directory of saving crash information. + * @param crashDir The directory of saving crash information. * @param onCrashListener The crash listener. */ public static void init(@NonNull final File crashDir, final OnCrashListener onCrashListener) { @@ -75,22 +73,23 @@ public static void init(@NonNull final File crashDir, final OnCrashListener onCr /** * Initialization * - * @param crashDirPath The directory's path of saving crash information. + * @param crashDirPath The directory's path of saving crash information. * @param onCrashListener The crash listener. */ public static void init(final String crashDirPath, final OnCrashListener onCrashListener) { String dirPath; if (UtilsBridge.isSpace(crashDirPath)) { if (UtilsBridge.isSDCardEnableByEnvironment() - && Utils.getApp().getExternalFilesDir(null) != null) + && Utils.getApp().getExternalFilesDir(null) != null) { dirPath = Utils.getApp().getExternalFilesDir(null) + FILE_SEP + "crash" + FILE_SEP; - else { + } else { dirPath = Utils.getApp().getFilesDir() + FILE_SEP + "crash" + FILE_SEP; } } else { dirPath = crashDirPath.endsWith(FILE_SEP) ? crashDirPath : crashDirPath + FILE_SEP; } - Thread.setDefaultUncaughtExceptionHandler(getUncaughtExceptionHandler(dirPath, onCrashListener)); + Thread.setDefaultUncaughtExceptionHandler( + getUncaughtExceptionHandler(dirPath, onCrashListener)); } private static UncaughtExceptionHandler getUncaughtExceptionHandler(final String dirPath, @@ -99,28 +98,16 @@ private static UncaughtExceptionHandler getUncaughtExceptionHandler(final String @Override public void uncaughtException(@NonNull final Thread t, @NonNull final Throwable e) { final String time = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss").format(new Date()); - final StringBuilder sb = new StringBuilder(); - final String head = "************* Log Head ****************" + - "\nTime Of Crash : " + time + - "\nDevice Manufacturer: " + Build.MANUFACTURER + - "\nDevice Model : " + Build.MODEL + - "\nAndroid Version : " + Build.VERSION.RELEASE + - "\nAndroid SDK : " + Build.VERSION.SDK_INT + - "\nApp VersionName : " + UtilsBridge.getAppVersionName() + - "\nApp VersionCode : " + UtilsBridge.getAppVersionCode() + - "\n************* Log Head ****************\n\n"; - sb.append(head).append(UtilsBridge.getFullStackTrace(e)); - final String crashInfo = sb.toString(); + CrashInfo info = new CrashInfo(time, e); final String crashFile = dirPath + time + ".txt"; - UtilsBridge.writeFileFromString(crashFile, crashInfo, true); - - if (onCrashListener != null) { - onCrashListener.onCrash(crashInfo, e); - } + UtilsBridge.writeFileFromString(crashFile, info.toString(), true); if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) { DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(t, e); } + if (onCrashListener != null) { + onCrashListener.onCrash(info); + } } }; } @@ -130,6 +117,34 @@ public void uncaughtException(@NonNull final Thread t, @NonNull final Throwable /////////////////////////////////////////////////////////////////////////// public interface OnCrashListener { - void onCrash(String crashInfo, Throwable e); + void onCrash(CrashInfo crashInfo); + } + + public static final class CrashInfo { + private UtilsBridge.FileHead mFileHeadProvider; + private Throwable mThrowable; + + private CrashInfo(String time, Throwable throwable) { + mThrowable = throwable; + mFileHeadProvider = new UtilsBridge.FileHead("Crash"); + mFileHeadProvider.addFirst("Time Of Crash", time); + } + + public final void addExtraHead(MapextraHead) { + mFileHeadProvider.append(extraHead); + } + + public final void addExtraHead(String key, String value) { + mFileHeadProvider.append(key, value); + } + + public final Throwable getThrowable() { + return mThrowable; + } + + @Override + public String toString() { + return mFileHeadProvider.toString() + UtilsBridge.getFullStackTrace(mThrowable); + } } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java new file mode 100644 index 0000000000..afc49b9c6f --- /dev/null +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java @@ -0,0 +1,86 @@ +package com.blankj.utilcode.util; + +import android.os.SystemClock; +import android.text.TextUtils; +import android.view.View; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import androidx.annotation.NonNull; + +/** + * + * author: Blankj + * blog : http://blankj.com + * time : 2020/09/01 + * desc : utils about debouncing + *+ */ +public class DebouncingUtils { + + private static final int CACHE_SIZE = 64; + private static final MapKEY_MILLIS_MAP = new ConcurrentHashMap<>(CACHE_SIZE); + private static final long DEBOUNCING_DEFAULT_VALUE = 1000; + + private DebouncingUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Return whether the view is not in a jitter state. + * + * @param view The view. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isValid(@NonNull final View view) { + return isValid(view, DEBOUNCING_DEFAULT_VALUE); + } + + /** + * Return whether the view is not in a jitter state. + * + * @param view The view. + * @param duration The duration. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isValid(@NonNull final View view, final long duration) { + return isValid(String.valueOf(view.hashCode()), duration); + } + + /** + * Return whether the key is not in a jitter state. + * + * @param key The key. + * @param duration The duration. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isValid(@NonNull String key, final long duration) { + if (TextUtils.isEmpty(key)) { + throw new IllegalArgumentException("The key is null."); + } + if (duration < 0) { + throw new IllegalArgumentException("The duration is less than 0."); + } + long curTime = SystemClock.elapsedRealtime(); + clearIfNecessary(curTime); + Long validTime = KEY_MILLIS_MAP.get(key); + if (validTime == null || curTime >= validTime) { + KEY_MILLIS_MAP.put(key, curTime + duration); + return true; + } + return false; + } + + private static void clearIfNecessary(long curTime) { + if (KEY_MILLIS_MAP.size() < CACHE_SIZE) return; + for (Iterator> it = KEY_MILLIS_MAP.entrySet().iterator(); it.hasNext(); ) { + Map.Entry entry = it.next(); + Long validTime = entry.getValue(); + if (curTime >= validTime) { + it.remove(); + } + } + } +} diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/DeviceUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DeviceUtils.java index 266734aa03..9cd01108e1 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/DeviceUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DeviceUtils.java @@ -10,18 +10,22 @@ import android.net.wifi.WifiManager; import android.os.Build; import android.provider.Settings; -import android.support.annotation.RequiresApi; -import android.support.annotation.RequiresPermission; import android.telephony.TelephonyManager; import android.text.TextUtils; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.UUID; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; + import static android.Manifest.permission.ACCESS_WIFI_STATE; import static android.Manifest.permission.CHANGE_WIFI_STATE; import static android.Manifest.permission.INTERNET; @@ -113,10 +117,10 @@ public static String getAndroidID() { * * @return the MAC address */ - @RequiresPermission(allOf = {ACCESS_WIFI_STATE, INTERNET, CHANGE_WIFI_STATE}) + @RequiresPermission(allOf = {ACCESS_WIFI_STATE, CHANGE_WIFI_STATE}) public static String getMacAddress() { String macAddress = getMacAddress((String[]) null); - if (!macAddress.equals("") || getWifiEnabled()) return macAddress; + if (!TextUtils.isEmpty(macAddress) || getWifiEnabled()) return macAddress; setWifiEnabled(true); setWifiEnabled(false); return getMacAddress((String[]) null); @@ -151,7 +155,7 @@ private static void setWifiEnabled(final boolean enabled) { * * @return the MAC address */ - @RequiresPermission(allOf = {ACCESS_WIFI_STATE, INTERNET}) + @RequiresPermission(allOf = {ACCESS_WIFI_STATE}) public static String getMacAddress(final String... excepts) { String macAddress = getMacAddressByNetworkInterface(); if (isAddressNotInExcepts(macAddress, excepts)) { @@ -173,25 +177,37 @@ public static String getMacAddress(final String... excepts) { } private static boolean isAddressNotInExcepts(final String address, final String... excepts) { + if (TextUtils.isEmpty(address)) { + return false; + } + if ("02:00:00:00:00:00".equals(address)) { + return false; + } if (excepts == null || excepts.length == 0) { - return !"02:00:00:00:00:00".equals(address); + return true; } for (String filter : excepts) { - if (address.equals(filter)) { + if (filter != null && filter.equals(address)) { return false; } } return true; } - @SuppressLint({"MissingPermission", "HardwareIds"}) + @RequiresPermission(ACCESS_WIFI_STATE) private static String getMacAddressByWifiInfo() { try { final WifiManager wifi = (WifiManager) Utils.getApp() .getApplicationContext().getSystemService(WIFI_SERVICE); if (wifi != null) { final WifiInfo info = wifi.getConnectionInfo(); - if (info != null) return info.getMacAddress(); + if (info != null) { + @SuppressLint("HardwareIds") + String macAddress = info.getMacAddress(); + if (!TextUtils.isEmpty(macAddress)) { + return macAddress; + } + } } } catch (Exception e) { e.printStackTrace(); @@ -369,6 +385,7 @@ public static boolean isEmulator() { intent.setAction(Intent.ACTION_DIAL); boolean checkDial = intent.resolveActivity(Utils.getApp().getPackageManager()) == null; if (checkDial) return true; + if (isEmulatorByCpu()) return true; // boolean checkDebuggerConnected = Debug.isDebuggerConnected(); // if (checkDebuggerConnected) return true; @@ -376,6 +393,55 @@ public static boolean isEmulator() { return false; } + /** + * Returns whether is emulator by check cpu info. + * by function of {@link #readCpuInfo}, obtain the device cpu information. + * then compare whether it is intel or amd (because intel and amd are generally not mobile phone cpu), to determine whether it is a real mobile phone + * + * @return {@code true}: yes
{@code false}: no + */ + private static boolean isEmulatorByCpu() { + String cpuInfo = readCpuInfo(); + return cpuInfo.contains("intel") || cpuInfo.contains("amd"); + } + + /** + * Return Cpu information + * + * @return Cpu info + */ + private static String readCpuInfo() { + String result = ""; + try { + String[] args = {"/system/bin/cat", "/proc/cpuinfo"}; + ProcessBuilder cmd = new ProcessBuilder(args); + Process process = cmd.start(); + StringBuilder sb = new StringBuilder(); + String readLine; + BufferedReader responseReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8")); + while ((readLine = responseReader.readLine()) != null) { + sb.append(readLine); + } + responseReader.close(); + result = sb.toString().toLowerCase(); + } catch (IOException ignored) { + } + return result; + } + + /** + * Whether user has enabled development settings. + * + * @return whether user has enabled development settings. + */ + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) + public static boolean isDevelopmentSettingsEnabled() { + return Settings.Global.getInt( + Utils.getApp().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0 + ) > 0; + } + private static final String KEY_UDID = "KEY_UDID"; private volatile static String udid; @@ -388,7 +454,6 @@ public static boolean isEmulator() { * * @return the unique device id */ - @SuppressLint({"MissingPermission", "HardwareIds"}) public static String getUniqueDeviceId() { return getUniqueDeviceId("", true); } @@ -402,7 +467,6 @@ public static String getUniqueDeviceId() { * @param prefix The prefix of the unique device id. * @return the unique device id */ - @SuppressLint({"MissingPermission", "HardwareIds"}) public static String getUniqueDeviceId(String prefix) { return getUniqueDeviceId(prefix, true); } @@ -416,7 +480,6 @@ public static String getUniqueDeviceId(String prefix) { * @param useCache True to use cache, false otherwise. * @return the unique device id */ - @SuppressLint({"MissingPermission", "HardwareIds"}) public static String getUniqueDeviceId(boolean useCache) { return getUniqueDeviceId("", useCache); } @@ -431,7 +494,6 @@ public static String getUniqueDeviceId(boolean useCache) { * @param useCache True to use cache, false otherwise. * @return the unique device id */ - @SuppressLint({"MissingPermission", "HardwareIds"}) public static String getUniqueDeviceId(String prefix, boolean useCache) { if (!useCache) { return getUniqueDeviceIdReal(prefix); @@ -462,7 +524,7 @@ private static String getUniqueDeviceIdReal(String prefix) { return saveUdid(prefix + 9, ""); } - @SuppressLint({"MissingPermission", "HardwareIds"}) + @RequiresPermission(allOf = {ACCESS_WIFI_STATE, INTERNET, CHANGE_WIFI_STATE}) public static boolean isSameDevice(final String uniqueDeviceId) { // {prefix}{type}{32id} if (TextUtils.isEmpty(uniqueDeviceId) && uniqueDeviceId.length() < 33) return false; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/EncryptUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/EncryptUtils.java index 14d8d0f377..933f8e4953 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/EncryptUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/EncryptUtils.java @@ -1,5 +1,7 @@ package com.blankj.utilcode.util; +import android.os.Build; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -10,15 +12,11 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; -import javax.crypto.BadPaddingException; import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; import javax.crypto.Mac; -import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; @@ -1085,12 +1083,18 @@ private static byte[] rsaTemplate(final byte[] data, } try { Key rsaKey; + KeyFactory keyFactory; + if (Build.VERSION.SDK_INT < 28) { + keyFactory = KeyFactory.getInstance("RSA", "BC"); + } else { + keyFactory = KeyFactory.getInstance("RSA"); + } if (isEncrypt) { X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key); - rsaKey = KeyFactory.getInstance("RSA").generatePublic(keySpec); + rsaKey = keyFactory.generatePublic(keySpec); } else { PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key); - rsaKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); + rsaKey = keyFactory.generatePrivate(keySpec); } if (rsaKey == null) return null; Cipher cipher = Cipher.getInstance(transformation); @@ -1123,17 +1127,7 @@ private static byte[] rsaTemplate(final byte[] data, } else { return cipher.doFinal(data); } - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - } catch (InvalidKeyException e) { - e.printStackTrace(); - } catch (BadPaddingException e) { - e.printStackTrace(); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - } catch (InvalidKeySpecException e) { + } catch (Exception e) { e.printStackTrace(); } return null; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileIOUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileIOUtils.java index 761550d0b6..ca786e0b98 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileIOUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileIOUtils.java @@ -376,7 +376,11 @@ public static boolean writeFileFromBytesByChannel(final File file, final byte[] bytes, final boolean append, final boolean isForce) { - if (bytes == null || !UtilsBridge.createOrExistsFile(file)) { + if (bytes == null) { + Log.e("FileIOUtils", "bytes is null."); + return false; + } + if (!UtilsBridge.createOrExistsFile(file)) { Log.e("FileIOUtils", "create file <" + file + "> failed."); return false; } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileUtils.java index f329e36b13..1acca1e050 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FileUtils.java @@ -430,12 +430,14 @@ private static boolean copyOrMoveDir(final File srcDir, if (!srcDir.exists() || !srcDir.isDirectory()) return false; if (!createOrExistsDir(destDir)) return false; File[] files = srcDir.listFiles(); - for (File file : files) { - File oneDestFile = new File(destPath + file.getName()); - if (file.isFile()) { - if (!copyOrMoveFile(file, oneDestFile, listener, isMove)) return false; - } else if (file.isDirectory()) { - if (!copyOrMoveDir(file, oneDestFile, listener, isMove)) return false; + if (files != null && files.length > 0) { + for (File file : files) { + File oneDestFile = new File(destPath + file.getName()); + if (file.isFile()) { + if (!copyOrMoveFile(file, oneDestFile, listener, isMove)) return false; + } else if (file.isDirectory()) { + if (!copyOrMoveDir(file, oneDestFile, listener, isMove)) return false; + } } } return !isMove || deleteDir(srcDir); @@ -506,7 +508,7 @@ private static boolean deleteDir(final File dir) { // dir isn't a directory then return false if (!dir.isDirectory()) return false; File[] files = dir.listFiles(); - if (files != null && files.length != 0) { + if (files != null && files.length > 0) { for (File file : files) { if (file.isFile()) { if (!file.delete()) return false; @@ -846,7 +848,7 @@ private static ListlistFilesInDirWithFilterInner(final File dir, List list = new ArrayList<>(); if (!isDir(dir)) return list; File[] files = dir.listFiles(); - if (files != null && files.length != 0) { + if (files != null && files.length > 0) { for (File file : files) { if (filter.accept(file)) { list.add(file); @@ -1166,10 +1168,10 @@ public static long getLength(final File file) { * @return the length of directory */ private static long getDirLength(final File dir) { - if (!isDir(dir)) return -1; + if (!isDir(dir)) return 0; long len = 0; File[] files = dir.listFiles(); - if (files != null && files.length != 0) { + if (files != null && files.length > 0) { for (File file : files) { if (file.isDirectory()) { len += getDirLength(file); @@ -1398,8 +1400,7 @@ public static void notifySystemToScan(final String filePath) { public static void notifySystemToScan(final File file) { if (file == null || !file.exists()) return; Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); - Uri uri = Uri.fromFile(file); - intent.setData(uri); + intent.setData(Uri.parse("file://" + file.getAbsolutePath())); Utils.getApp().sendBroadcast(intent); } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FlashlightUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FlashlightUtils.java index 1b864f6ef5..e74996d4e4 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FlashlightUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FlashlightUtils.java @@ -65,7 +65,7 @@ public static void setFlashlightStatus(final boolean isOn) { parameters.setFlashMode(FLASH_MODE_TORCH); mCamera.setParameters(parameters); } catch (IOException e) { - Log.e("FlashlightUtils", "setFlashlightStatusOn: ", e); + e.printStackTrace(); } } } else { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FragmentUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FragmentUtils.java index 0916aa3b1d..31bbac1217 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/FragmentUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FragmentUtils.java @@ -3,23 +3,25 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.annotation.AnimRes; -import android.support.annotation.AnimatorRes; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.View; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import androidx.annotation.AnimRes; +import androidx.annotation.AnimatorRes; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + /** * * author: Blankj @@ -301,7 +303,7 @@ public static void add(@NonNull final FragmentManager fm, final boolean isHide, final boolean isAddStack) { putArgs(add, new Args(containerId, tag, isHide, isAddStack)); - operateNoAnim(fm, TYPE_ADD_FRAGMENT, null, add); + operateNoAnim(TYPE_ADD_FRAGMENT, fm, null, add); } /** @@ -489,7 +491,7 @@ public static void add(@NonNull final FragmentManager fm, putArgs(adds[i], new Args(containerId, tags[i], showIndex != i, false)); } } - operateNoAnim(fm, TYPE_ADD_FRAGMENT, null, adds); + operateNoAnim(TYPE_ADD_FRAGMENT, fm, null, adds); } /** @@ -499,7 +501,7 @@ public static void add(@NonNull final FragmentManager fm, */ public static void show(@NonNull final Fragment show) { putArgs(show, false); - operateNoAnim(show.getFragmentManager(), TYPE_SHOW_FRAGMENT, null, show); + operateNoAnim(TYPE_SHOW_FRAGMENT, show.getFragmentManager(), null, show); } /** @@ -512,11 +514,7 @@ public static void show(@NonNull final FragmentManager fm) { for (Fragment show : fragments) { putArgs(show, false); } - operateNoAnim(fm, - TYPE_SHOW_FRAGMENT, - null, - fragments.toArray(new Fragment[0]) - ); + operateNoAnim(TYPE_SHOW_FRAGMENT, fm, null, fragments.toArray(new Fragment[0])); } /** @@ -526,7 +524,7 @@ public static void show(@NonNull final FragmentManager fm) { */ public static void hide(@NonNull final Fragment hide) { putArgs(hide, true); - operateNoAnim(hide.getFragmentManager(), TYPE_HIDE_FRAGMENT, null, hide); + operateNoAnim(TYPE_HIDE_FRAGMENT, hide.getFragmentManager(), null, hide); } /** @@ -539,21 +537,28 @@ public static void hide(@NonNull final FragmentManager fm) { for (Fragment hide : fragments) { putArgs(hide, true); } - operateNoAnim(fm, - TYPE_HIDE_FRAGMENT, - null, - fragments.toArray(new Fragment[0]) - ); + operateNoAnim(TYPE_HIDE_FRAGMENT, fm, null, fragments.toArray(new Fragment[0])); + } + + /** + * Show fragment then hide other fragment. + * + * @param show The fragment will be show. + * @param hide The fragment will be hide. + */ + public static void showHide(@NonNull final Fragment show, + @NonNull final Fragment hide) { + showHide(show, Collections.singletonList(hide)); } /** * Show fragment then hide other fragment. * * @param showIndex The index of fragment will be shown. - * @param fragments The fragments will be hide. + * @param fragments The fragment will be hide. */ - public static void showHide(final int showIndex, @NonNull final Listfragments) { - showHide(fragments.get(showIndex), fragments); + public static void showHide(final int showIndex, @NonNull final Fragment... fragments) { + showHide(fragments[showIndex], fragments); } /** @@ -562,22 +567,18 @@ public static void showHide(final int showIndex, @NonNull final List f * @param show The fragment will be show. * @param hide The fragment will be hide. */ - public static void showHide(@NonNull final Fragment show, @NonNull final List hide) { - for (Fragment fragment : hide) { - putArgs(fragment, fragment != show); - } - operateNoAnim(show.getFragmentManager(), TYPE_SHOW_HIDE_FRAGMENT, show, - hide.toArray(new Fragment[0])); + public static void showHide(@NonNull final Fragment show, @NonNull final Fragment... hide) { + showHide(show, Arrays.asList(hide)); } /** * Show fragment then hide other fragment. * * @param showIndex The index of fragment will be shown. - * @param fragments The fragment will be hide. + * @param fragments The fragments will be hide. */ - public static void showHide(final int showIndex, @NonNull final Fragment... fragments) { - showHide(fragments[showIndex], fragments); + public static void showHide(final int showIndex, @NonNull final List fragments) { + showHide(fragments.get(showIndex), fragments); } /** @@ -586,13 +587,14 @@ public static void showHide(final int showIndex, @NonNull final Fragment... frag * @param show The fragment will be show. * @param hide The fragment will be hide. */ - public static void showHide(@NonNull final Fragment show, @NonNull final Fragment... hide) { + public static void showHide(@NonNull final Fragment show, @NonNull final List hide) { for (Fragment fragment : hide) { putArgs(fragment, fragment != show); } - operateNoAnim(show.getFragmentManager(), TYPE_SHOW_HIDE_FRAGMENT, show, hide); + operateNoAnim(TYPE_SHOW_HIDE_FRAGMENT, show.getFragmentManager(), show, hide.toArray(new Fragment[0])); } + /** * Show fragment then hide other fragment. * @@ -600,10 +602,47 @@ public static void showHide(@NonNull final Fragment show, @NonNull final Fragmen * @param hide The fragment will be hide. */ public static void showHide(@NonNull final Fragment show, - @NonNull final Fragment hide) { - putArgs(show, false); - putArgs(hide, true); - operateNoAnim(show.getFragmentManager(), TYPE_SHOW_HIDE_FRAGMENT, show, hide); + @NonNull final Fragment hide, @AnimatorRes @AnimRes final int enterAnim, + @AnimatorRes @AnimRes final int exitAnim, + @AnimatorRes @AnimRes final int popEnterAnim, + @AnimatorRes @AnimRes final int popExitAnim) { + showHide(show, Collections.singletonList(hide), enterAnim, exitAnim, popEnterAnim, popExitAnim); + } + + /** + * Show fragment then hide other fragment. + * + * @param showIndex The index of fragment will be shown. + * @param fragments The fragments will be hide. + */ + public static void showHide(final int showIndex, @NonNull final List fragments, + @AnimatorRes @AnimRes final int enterAnim, + @AnimatorRes @AnimRes final int exitAnim, + @AnimatorRes @AnimRes final int popEnterAnim, + @AnimatorRes @AnimRes final int popExitAnim) { + showHide(fragments.get(showIndex), fragments, enterAnim, exitAnim, popEnterAnim, popExitAnim); + } + + /** + * Show fragment then hide other fragment. + * + * @param show The fragment will be show. + * @param hide The fragment will be hide. + */ + public static void showHide(@NonNull final Fragment show, @NonNull final List hide, + @AnimatorRes @AnimRes final int enterAnim, + @AnimatorRes @AnimRes final int exitAnim, + @AnimatorRes @AnimRes final int popEnterAnim, + @AnimatorRes @AnimRes final int popExitAnim) { + for (Fragment fragment : hide) { + putArgs(fragment, fragment != show); + } + FragmentManager fm = show.getFragmentManager(); + if (fm != null) { + FragmentTransaction ft = fm.beginTransaction(); + addAnim(ft, enterAnim, exitAnim, popEnterAnim, popExitAnim); + operate(TYPE_SHOW_HIDE_FRAGMENT, fm, ft, show, hide.toArray(new Fragment[0])); + } } /** @@ -1357,7 +1396,7 @@ public static void popAll(@NonNull final FragmentManager fm, final boolean isImm * @param remove The fragment will be removed. */ public static void remove(@NonNull final Fragment remove) { - operateNoAnim(remove.getFragmentManager(), TYPE_REMOVE_FRAGMENT, null, remove); + operateNoAnim(TYPE_REMOVE_FRAGMENT, remove.getFragmentManager(), null, remove); } /** @@ -1367,8 +1406,7 @@ public static void remove(@NonNull final Fragment remove) { * @param isIncludeSelf True to include the fragment, false otherwise. */ public static void removeTo(@NonNull final Fragment removeTo, final boolean isIncludeSelf) { - operateNoAnim(removeTo.getFragmentManager(), TYPE_REMOVE_TO_FRAGMENT, - isIncludeSelf ? removeTo : null, removeTo); + operateNoAnim(TYPE_REMOVE_TO_FRAGMENT, removeTo.getFragmentManager(), isIncludeSelf ? removeTo : null, removeTo); } /** @@ -1378,11 +1416,7 @@ public static void removeTo(@NonNull final Fragment removeTo, final boolean isIn */ public static void removeAll(@NonNull final FragmentManager fm) { List fragments = getFragments(fm); - operateNoAnim(fm, - TYPE_REMOVE_FRAGMENT, - null, - fragments.toArray(new Fragment[0]) - ); + operateNoAnim(TYPE_REMOVE_FRAGMENT, fm, null, fragments.toArray(new Fragment[0])); } private static void putArgs(final Fragment fragment, final Args args) { @@ -1414,8 +1448,7 @@ private static Args getArgs(final Fragment fragment) { bundle.getBoolean(ARGS_IS_ADD_STACK)); } - private static void operateNoAnim(@Nullable final FragmentManager fm, - final int type, + private static void operateNoAnim(final int type, @Nullable final FragmentManager fm, final Fragment src, Fragment... dest) { if (fm == null) return; @@ -1493,6 +1526,7 @@ private static void operate(final int type, break; } ft.commitAllowingStateLoss(); + fm.executePendingTransactions(); } private static void addAnim(final FragmentTransaction ft, diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/GsonUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/GsonUtils.java index 6576ee2801..c3eb0684c6 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/GsonUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/GsonUtils.java @@ -1,6 +1,5 @@ package com.blankj.utilcode.util; -import android.support.annotation.NonNull; import android.text.TextUtils; import com.google.gson.Gson; @@ -14,6 +13,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import androidx.annotation.NonNull; + /** * diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ImageUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ImageUtils.java index c7603ea601..e0d472428f 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ImageUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ImageUtils.java @@ -1,5 +1,7 @@ package com.blankj.utilcode.util; +import android.Manifest; +import android.content.ContentValues; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; @@ -12,6 +14,7 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -22,18 +25,15 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.ExifInterface; +import android.net.Uri; import android.os.Build; +import android.os.Environment; +import android.provider.MediaStore; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlur; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.annotation.FloatRange; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; -import android.support.v4.content.ContextCompat; +import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -47,6 +47,15 @@ import java.io.InputStream; import java.io.OutputStream; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.FloatRange; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.content.ContextCompat; + /** ** author: Blankj @@ -79,7 +88,7 @@ public static byte[] bitmap2Bytes(final Bitmap bitmap) { * @param quality The quality. * @return bytes */ - public static byte[] bitmap2Bytes(final Bitmap bitmap, final CompressFormat format, int quality) { + public static byte[] bitmap2Bytes(@Nullable final Bitmap bitmap, @NonNull final CompressFormat format, int quality) { if (bitmap == null) return null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(format, quality, baos); @@ -92,7 +101,7 @@ public static byte[] bitmap2Bytes(final Bitmap bitmap, final CompressFormat form * @param bytes The bytes. * @return bitmap */ - public static Bitmap bytes2Bitmap(final byte[] bytes) { + public static Bitmap bytes2Bitmap(@Nullable final byte[] bytes) { return (bytes == null || bytes.length == 0) ? null : BitmapFactory.decodeByteArray(bytes, 0, bytes.length); @@ -104,7 +113,8 @@ public static Bitmap bytes2Bitmap(final byte[] bytes) { * @param drawable The drawable. * @return bitmap */ - public static Bitmap drawable2Bitmap(final Drawable drawable) { + public static Bitmap drawable2Bitmap(@Nullable final Drawable drawable) { + if (drawable == null) return null; if (drawable instanceof BitmapDrawable) { BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; if (bitmapDrawable.getBitmap() != null) { @@ -136,7 +146,7 @@ public static Bitmap drawable2Bitmap(final Drawable drawable) { * @param bitmap The bitmap. * @return drawable */ - public static Drawable bitmap2Drawable(final Bitmap bitmap) { + public static Drawable bitmap2Drawable(@Nullable final Bitmap bitmap) { return bitmap == null ? null : new BitmapDrawable(Utils.getApp().getResources(), bitmap); } @@ -146,7 +156,7 @@ public static Drawable bitmap2Drawable(final Bitmap bitmap) { * @param drawable The drawable. * @return bytes */ - public static byte[] drawable2Bytes(final Drawable drawable) { + public static byte[] drawable2Bytes(@Nullable final Drawable drawable) { return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable)); } @@ -185,23 +195,22 @@ public static Bitmap view2Bitmap(final View view) { view.setWillNotCacheDrawing(false); Bitmap drawingCache = view.getDrawingCache(); Bitmap bitmap; - if (null == drawingCache) { + if (null == drawingCache || drawingCache.isRecycled()) { view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.buildDrawingCache(); drawingCache = view.getDrawingCache(); - if (drawingCache != null) { - bitmap = Bitmap.createBitmap(drawingCache); - } else { - bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888); + if (null == drawingCache || drawingCache.isRecycled()) { + bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); view.draw(canvas); + } else { + bitmap = Bitmap.createBitmap(drawingCache); } } else { bitmap = Bitmap.createBitmap(drawingCache); } - view.destroyDrawingCache(); view.setWillNotCacheDrawing(willNotCacheDrawing); view.setDrawingCacheEnabled(drawingCacheEnabled); return bitmap; @@ -336,6 +345,9 @@ public static Bitmap getBitmap(final byte[] data, */ public static Bitmap getBitmap(@DrawableRes final int resId) { Drawable drawable = ContextCompat.getDrawable(Utils.getApp(), resId); + if (drawable == null) { + return null; + } Canvas canvas = new Canvas(); Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), @@ -786,11 +798,27 @@ public static Bitmap toRoundCorner(final Bitmap src, */ public static Bitmap toRoundCorner(final Bitmap src, final float radius, - @IntRange(from = 0) int borderSize, + @FloatRange(from = 0) float borderSize, @ColorInt int borderColor) { return toRoundCorner(src, radius, borderSize, borderColor, false); } + /** + * Return the round corner bitmap. + * + * @param src The source of bitmap. + * @param radii Array of 8 values, 4 pairs of [X,Y] radii + * @param borderSize The size of border. + * @param borderColor The color of border. + * @return the round corner bitmap + */ + public static Bitmap toRoundCorner(final Bitmap src, + final float[] radii, + @FloatRange(from = 0) float borderSize, + @ColorInt int borderColor) { + return toRoundCorner(src, radii, borderSize, borderColor, false); + } + /** * Return the round corner bitmap. * @@ -803,7 +831,26 @@ public static Bitmap toRoundCorner(final Bitmap src, */ public static Bitmap toRoundCorner(final Bitmap src, final float radius, - @IntRange(from = 0) int borderSize, + @FloatRange(from = 0) float borderSize, + @ColorInt int borderColor, + final boolean recycle) { + float[] radii = {radius, radius, radius, radius, radius, radius, radius, radius}; + return toRoundCorner(src, radii, borderSize, borderColor, recycle); + } + + /** + * Return the round corner bitmap. + * + * @param src The source of bitmap. + * @param radii Array of 8 values, 4 pairs of [X,Y] radii + * @param borderSize The size of border. + * @param borderColor The color of border. + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the round corner bitmap + */ + public static Bitmap toRoundCorner(final Bitmap src, + final float[] radii, + @FloatRange(from = 0) float borderSize, @ColorInt int borderColor, final boolean recycle) { if (isEmptyBitmap(src)) return null; @@ -817,14 +864,16 @@ public static Bitmap toRoundCorner(final Bitmap src, RectF rectF = new RectF(0, 0, width, height); float halfBorderSize = borderSize / 2f; rectF.inset(halfBorderSize, halfBorderSize); - canvas.drawRoundRect(rectF, radius, radius, paint); + Path path = new Path(); + path.addRoundRect(rectF, radii, Path.Direction.CW); + canvas.drawPath(path, paint); if (borderSize > 0) { paint.setShader(null); paint.setColor(borderColor); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(borderSize); paint.setStrokeCap(Paint.Cap.ROUND); - canvas.drawRoundRect(rectF, radius, radius, paint); + canvas.drawPath(path, paint); } if (recycle && !src.isRecycled() && ret != src) src.recycle(); return ret; @@ -840,12 +889,46 @@ public static Bitmap toRoundCorner(final Bitmap src, * @return the round corner bitmap with border */ public static Bitmap addCornerBorder(final Bitmap src, - @IntRange(from = 1) final int borderSize, + @FloatRange(from = 1) final float borderSize, @ColorInt final int color, @FloatRange(from = 0) final float cornerRadius) { return addBorder(src, borderSize, color, false, cornerRadius, false); } + /** + * Return the round corner bitmap with border. + * + * @param src The source of bitmap. + * @param borderSize The size of border. + * @param color The color of border. + * @param radii Array of 8 values, 4 pairs of [X,Y] radii + * @return the round corner bitmap with border + */ + public static Bitmap addCornerBorder(final Bitmap src, + @FloatRange(from = 1) final float borderSize, + @ColorInt final int color, + final float[] radii) { + return addBorder(src, borderSize, color, false, radii, false); + } + + /** + * Return the round corner bitmap with border. + * + * @param src The source of bitmap. + * @param borderSize The size of border. + * @param color The color of border. + * @param radii Array of 8 values, 4 pairs of [X,Y] radii + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the round corner bitmap with border + */ + public static Bitmap addCornerBorder(final Bitmap src, + @FloatRange(from = 1) final float borderSize, + @ColorInt final int color, + final float[] radii, + final boolean recycle) { + return addBorder(src, borderSize, color, false, radii, recycle); + } + /** * Return the round corner bitmap with border. * @@ -857,7 +940,7 @@ public static Bitmap addCornerBorder(final Bitmap src, * @return the round corner bitmap with border */ public static Bitmap addCornerBorder(final Bitmap src, - @IntRange(from = 1) final int borderSize, + @FloatRange(from = 1) final float borderSize, @ColorInt final int color, @FloatRange(from = 0) final float cornerRadius, final boolean recycle) { @@ -873,7 +956,7 @@ public static Bitmap addCornerBorder(final Bitmap src, * @return the round bitmap with border */ public static Bitmap addCircleBorder(final Bitmap src, - @IntRange(from = 1) final int borderSize, + @FloatRange(from = 1) final float borderSize, @ColorInt final int color) { return addBorder(src, borderSize, color, true, 0, false); } @@ -888,7 +971,7 @@ public static Bitmap addCircleBorder(final Bitmap src, * @return the round bitmap with border */ public static Bitmap addCircleBorder(final Bitmap src, - @IntRange(from = 1) final int borderSize, + @FloatRange(from = 1) final float borderSize, @ColorInt final int color, final boolean recycle) { return addBorder(src, borderSize, color, true, 0, recycle); @@ -906,11 +989,33 @@ public static Bitmap addCircleBorder(final Bitmap src, * @return the bitmap with border */ private static Bitmap addBorder(final Bitmap src, - @IntRange(from = 1) final int borderSize, + @FloatRange(from = 1) final float borderSize, @ColorInt final int color, final boolean isCircle, final float cornerRadius, final boolean recycle) { + float[] radii = {cornerRadius, cornerRadius, cornerRadius, cornerRadius, + cornerRadius, cornerRadius, cornerRadius, cornerRadius}; + return addBorder(src, borderSize, color, isCircle, radii, recycle); + } + + /** + * Return the bitmap with border. + * + * @param src The source of bitmap. + * @param borderSize The size of border. + * @param color The color of border. + * @param isCircle True to draw circle, false to draw corner. + * @param radii Array of 8 values, 4 pairs of [X,Y] radii + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the bitmap with border + */ + private static Bitmap addBorder(final Bitmap src, + @FloatRange(from = 1) final float borderSize, + @ColorInt final int color, + final boolean isCircle, + final float[] radii, + final boolean recycle) { if (isEmptyBitmap(src)) return null; Bitmap ret = recycle ? src : src.copy(src.getConfig(), true); int width = ret.getWidth(); @@ -924,10 +1029,12 @@ private static Bitmap addBorder(final Bitmap src, float radius = Math.min(width, height) / 2f - borderSize / 2f; canvas.drawCircle(width / 2f, height / 2f, radius, paint); } else { - int halfBorderSize = borderSize >> 1; - RectF rectF = new RectF(halfBorderSize, halfBorderSize, - width - halfBorderSize, height - halfBorderSize); - canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint); + RectF rectF = new RectF(0, 0, width, height); + float halfBorderSize = borderSize / 2f; + rectF.inset(halfBorderSize, halfBorderSize); + Path path = new Path(); + path.addRoundRect(rectF, radii, Path.Direction.CW); + canvas.drawPath(path, paint); } return ret; } @@ -1501,7 +1608,7 @@ public static Bitmap stackBlur(final Bitmap src, int radius, final boolean recyc public static boolean save(final Bitmap src, final String filePath, final CompressFormat format) { - return save(src, UtilsBridge.getFileByPath(filePath), format, false); + return save(src, filePath, format, 100, false); } /** @@ -1513,7 +1620,39 @@ public static boolean save(final Bitmap src, * @return {@code true}: success
{@code false}: fail */ public static boolean save(final Bitmap src, final File file, final CompressFormat format) { - return save(src, file, format, false); + return save(src, file, format, 100, false); + } + + /** + * Save the bitmap. + * + * @param src The source of bitmap. + * @param filePath The path of file. + * @param format The format of the image. + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean save(final Bitmap src, + final String filePath, + final CompressFormat format, + final boolean recycle) { + return save(src, filePath, format, 100, recycle); + } + + /** + * Save the bitmap. + * + * @param src The source of bitmap. + * @param file The file. + * @param format The format of the image. + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean save(final Bitmap src, + final File file, + final CompressFormat format, + final boolean recycle) { + return save(src, file, format, 100, recycle); } /** @@ -1522,14 +1661,53 @@ public static boolean save(final Bitmap src, final File file, final CompressForm * @param src The source of bitmap. * @param filePath The path of file. * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting + * @return {@code true}: success
{@code false}: fail + */ + public static boolean save(final Bitmap src, + final String filePath, + final CompressFormat format, + final int quality) { + return save(src, UtilsBridge.getFileByPath(filePath), format, quality, false); + } + + /** + * Save the bitmap. + * + * @param src The source of bitmap. + * @param file The file. + * @param format The format of the image. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean save(final Bitmap src, + final File file, + final CompressFormat format, + final int quality) { + return save(src, file, format, quality, false); + } + + /** + * Save the bitmap. + * + * @param src The source of bitmap. + * @param filePath The path of file. + * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting * @param recycle True to recycle the source of bitmap, false otherwise. * @return {@code true}: success
{@code false}: fail */ public static boolean save(final Bitmap src, final String filePath, final CompressFormat format, + final int quality, final boolean recycle) { - return save(src, UtilsBridge.getFileByPath(filePath), format, recycle); + return save(src, UtilsBridge.getFileByPath(filePath), format, quality, recycle); } /** @@ -1538,14 +1716,27 @@ public static boolean save(final Bitmap src, * @param src The source of bitmap. * @param file The file. * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting * @param recycle True to recycle the source of bitmap, false otherwise. * @return {@code true}: success
{@code false}: fail */ public static boolean save(final Bitmap src, final File file, final CompressFormat format, + final int quality, final boolean recycle) { - if (isEmptyBitmap(src) || !UtilsBridge.createFileByDeleteOldFile(file)) { + if (isEmptyBitmap(src)) { + Log.e("ImageUtils", "bitmap is empty."); + return false; + } + if (src.isRecycled()) { + Log.e("ImageUtils", "bitmap is recycled."); + return false; + } + if (!UtilsBridge.createFileByDeleteOldFile(file)) { Log.e("ImageUtils", "create or delete file <" + file + "> failed."); return false; } @@ -1553,7 +1744,7 @@ public static boolean save(final Bitmap src, boolean ret = false; try { os = new BufferedOutputStream(new FileOutputStream(file)); - ret = src.compress(format, 100, os); + ret = src.compress(format, quality, os); if (recycle && !src.isRecycled()) src.recycle(); } catch (IOException e) { e.printStackTrace(); @@ -1569,6 +1760,184 @@ public static boolean save(final Bitmap src, return ret; } + /** + * @param src The source of bitmap. + * @param format The format of the image. + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final CompressFormat format) { + return save2Album(src, "", format, 100, false); + } + + /** + * @param src The source of bitmap. + * @param format The format of the image. + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final CompressFormat format, + final boolean recycle) { + return save2Album(src, "", format, 100, recycle); + } + + /** + * @param src The source of bitmap. + * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final CompressFormat format, + final int quality) { + return save2Album(src, "", format, quality, false); + } + + /** + * @param src The source of bitmap. + * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final CompressFormat format, + final int quality, + final boolean recycle) { + return save2Album(src, "", format, quality, recycle); + } + + /** + * @param src The source of bitmap. + * @param dirName The name of directory. + * @param format The format of the image. + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final String dirName, + final CompressFormat format) { + return save2Album(src, dirName, format, 100, false); + } + + /** + * @param src The source of bitmap. + * @param dirName The name of directory. + * @param format The format of the image. + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final String dirName, + final CompressFormat format, + final boolean recycle) { + return save2Album(src, dirName, format, 100, recycle); + } + + /** + * @param src The source of bitmap. + * @param dirName The name of directory. + * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final String dirName, + final CompressFormat format, + final int quality) { + return save2Album(src, dirName, format, quality, false); + } + + /** + * @param src The source of bitmap. + * @param dirName The name of directory. + * @param format The format of the image. + * @param quality Hint to the compressor, 0-100. 0 meaning compress for + * small size, 100 meaning compress for max quality. Some + * formats, like PNG which is lossless, will ignore the + * quality setting + * @param recycle True to recycle the source of bitmap, false otherwise. + * @return the file if save success, otherwise return null. + */ + @Nullable + public static File save2Album(final Bitmap src, + final String dirName, + final CompressFormat format, + final int quality, + final boolean recycle) { + String safeDirName = TextUtils.isEmpty(dirName) ? Utils.getApp().getPackageName() : dirName; + String suffix = CompressFormat.JPEG.equals(format) ? "JPG" : format.name(); + String fileName = System.currentTimeMillis() + "_" + quality + "." + suffix; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (!UtilsBridge.isGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + Log.e("ImageUtils", "save to album need storage permission"); + return null; + } + File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); + File destFile = new File(picDir, safeDirName + "/" + fileName); + if (!save(src, destFile, format, quality, recycle)) { + return null; + } + UtilsBridge.notifySystemToScan(destFile); + return destFile; + } else { + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); + contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*"); + Uri contentUri; + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else { + contentUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI; + } + contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/" + safeDirName); + contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1); + Uri uri = Utils.getApp().getContentResolver().insert(contentUri, contentValues); + if (uri == null) { + return null; + } + OutputStream os = null; + try { + os = Utils.getApp().getContentResolver().openOutputStream(uri); + src.compress(format, quality, os); + + contentValues.clear(); + contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0); + Utils.getApp().getContentResolver().update(uri, contentValues, null, null); + + return UtilsBridge.uri2File(uri); + } catch (Exception e) { + Utils.getApp().getContentResolver().delete(uri, null, null); + e.printStackTrace(); + return null; + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + /** * Return whether it is a image according to the file name. * diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/IntentUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/IntentUtils.java index 84224db4f9..a5009c3cba 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/IntentUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/IntentUtils.java @@ -8,14 +8,17 @@ import android.os.Bundle; import android.provider.MediaStore; import android.provider.Settings; -import android.support.annotation.RequiresPermission; -import android.support.v4.content.FileProvider; import java.io.File; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresPermission; +import androidx.core.content.FileProvider; + import static android.Manifest.permission.CALL_PHONE; /** @@ -66,18 +69,33 @@ public static Intent getInstallAppIntent(final String filePath) { * @return the intent of install app */ public static Intent getInstallAppIntent(final File file) { - if (file == null) return null; - Intent intent = new Intent(Intent.ACTION_VIEW); - Uri data; - String type = "application/vnd.android.package-archive"; + if (!UtilsBridge.isFileExists(file)) return null; + Uri uri; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - data = Uri.fromFile(file); + uri = Uri.fromFile(file); } else { + String authority = Utils.getApp().getPackageName() + ".utilcode.fileprovider"; + uri = FileProvider.getUriForFile(Utils.getApp(), authority, file); + } + return getInstallAppIntent(uri); + } + + /** + * Return the intent of install app. + *Target APIs greater than 25 must hold + * {@code
+ * + * @param uri The uri. + * @return the intent of install app + */ + public static Intent getInstallAppIntent(final Uri uri) { + if (uri == null) return null; + Intent intent = new Intent(Intent.ACTION_VIEW); + String type = "application/vnd.android.package-archive"; + intent.setDataAndType(uri, type); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - String authority = Utils.getApp().getPackageName() + ".utilcode.provider"; - data = FileProvider.getUriForFile(Utils.getApp(), authority, file); } - intent.setDataAndType(data, type); return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } @@ -117,9 +135,19 @@ public static Intent getLaunchAppIntent(final String pkgName) { * @return the intent of launch app details settings */ public static Intent getLaunchAppDetailsSettingsIntent(final String pkgName) { + return getLaunchAppDetailsSettingsIntent(pkgName, false); + } + + /** + * Return the intent of launch app details settings. + * + * @param pkgName The name of the package. + * @return the intent of launch app details settings + */ + public static Intent getLaunchAppDetailsSettingsIntent(final String pkgName, final boolean isNewTask) { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + pkgName)); - return getIntent(intent, true); + return getIntent(intent, isNewTask); } /** @@ -128,14 +156,44 @@ public static Intent getLaunchAppDetailsSettingsIntent(final String pkgName) { * @param content The content. * @return the intent of share text */ - public static Intent getShareTextIntent(final String content) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, content); + intent = Intent.createChooser(intent, ""); return getIntent(intent, true); } + /** + * Return the intent of share image. + * + * @param imagePath The path of image. + * @return the intent of share image + */ + public static Intent getShareImageIntent(final String imagePath) { + return getShareTextImageIntent("", imagePath); + } + + /** + * Return the intent of share image. + * + * @param imageFile The file of image. + * @return the intent of share image + */ + public static Intent getShareImageIntent(final File imageFile) { + return getShareTextImageIntent("", imageFile); + } + + /** + * Return the intent of share image. + * + * @param imageUri The uri of image. + * @return the intent of share image + */ + public static Intent getShareImageIntent(final Uri imageUri) { + return getShareTextImageIntent("", imageUri); + } + /** * Return the intent of share image. * @@ -143,38 +201,67 @@ public static Intent getShareTextIntent(final String content) { * @param imagePath The path of image. * @return the intent of share image */ - public static Intent getShareImageIntent(final String content, final String imagePath) { - if (UtilsBridge.isSpace(imagePath)) return null; - return getShareImageIntent(content, new File(imagePath)); + public static Intent getShareTextImageIntent(@Nullable final String content, final String imagePath) { + return getShareTextImageIntent(content, UtilsBridge.getFileByPath(imagePath)); } /** * Return the intent of share image. * - * @param content The content. - * @param image The file of image. + * @param content The content. + * @param imageFile The file of image. * @return the intent of share image */ - public static Intent getShareImageIntent(final String content, final File image) { - if (image == null || !image.isFile()) return null; - return getShareImageIntent(content, UtilsBridge.file2Uri(image)); + public static Intent getShareTextImageIntent(@Nullable final String content, final File imageFile) { + return getShareTextImageIntent(content, UtilsBridge.file2Uri(imageFile)); } /** * Return the intent of share image. * - * @param content The content. - * @param uri The uri of image. + * @param content The content. + * @param imageUri The uri of image. * @return the intent of share image */ - public static Intent getShareImageIntent(final String content, final Uri uri) { + public static Intent getShareTextImageIntent(@Nullable final String content, final Uri imageUri) { Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, content); - intent.putExtra(Intent.EXTRA_STREAM, uri); + intent.putExtra(Intent.EXTRA_STREAM, imageUri); intent.setType("image/*"); + intent = Intent.createChooser(intent, ""); return getIntent(intent, true); } + /** + * Return the intent of share images. + * + * @param imagePaths The paths of images. + * @return the intent of share images + */ + public static Intent getShareImageIntent(final LinkedList} imagePaths) { + return getShareTextImageIntent("", imagePaths); + } + + /** + * Return the intent of share images. + * + * @param images The files of images. + * @return the intent of share images + */ + public static Intent getShareImageIntent(final List images) { + return getShareTextImageIntent("", images); + } + + /** + * Return the intent of share images. + * + * @param uris The uris of image. + * @return the intent of share image + */ + public static Intent getShareImageIntent(final ArrayList uris) { + return getShareTextImageIntent("", uris); + } + /** * Return the intent of share images. * @@ -182,14 +269,18 @@ public static Intent getShareImageIntent(final String content, final Uri uri) { * @param imagePaths The paths of images. * @return the intent of share images */ - public static Intent getShareImageIntent(final String content, - final LinkedList imagePaths) { - if (imagePaths == null || imagePaths.isEmpty()) return null; + public static Intent getShareTextImageIntent(@Nullable final String content, + final LinkedList imagePaths) { List files = new ArrayList<>(); - for (String imagePath : imagePaths) { - files.add(new File(imagePath)); + if (imagePaths != null) { + for (String imagePath : imagePaths) { + File file = UtilsBridge.getFileByPath(imagePath); + if (file != null) { + files.add(file); + } + } } - return getShareImageIntent(content, files); + return getShareTextImageIntent(content, files); } /** @@ -199,14 +290,17 @@ public static Intent getShareImageIntent(final String content, * @param images The files of images. * @return the intent of share images */ - public static Intent getShareImageIntent(final String content, final List images) { - if (images == null || images.isEmpty()) return null; + public static Intent getShareTextImageIntent(@Nullable final String content, final List images) { ArrayList uris = new ArrayList<>(); - for (File image : images) { - if (!image.isFile()) continue; - uris.add(UtilsBridge.file2Uri(image)); + if (images != null) { + for (File image : images) { + Uri uri = UtilsBridge.file2Uri(image); + if (uri != null) { + uris.add(uri); + } + } } - return getShareImageIntent(content, uris); + return getShareTextImageIntent(content, uris); } /** @@ -216,11 +310,12 @@ public static Intent getShareImageIntent(final String content, final List * @param uris The uris of image. * @return the intent of share image */ - public static Intent getShareImageIntent(final String content, final ArrayList uris) { + public static Intent getShareTextImageIntent(@Nullable final String content, final ArrayList uris) { Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); intent.putExtra(Intent.EXTRA_TEXT, content); intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); intent.setType("image/*"); + intent = Intent.createChooser(intent, ""); return getIntent(intent, true); } @@ -295,9 +390,9 @@ public static Intent getComponentIntent(final String pkgName, public static Intent getShutdownIntent() { Intent intent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - intent = new Intent(Intent.ACTION_SHUTDOWN); - } else { intent = new Intent("com.android.internal.intent.action.REQUEST_SHUTDOWN"); + } else { + intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN"); } intent.putExtra("android.intent.extra.KEY_CONFIRM", false); return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -309,8 +404,8 @@ public static Intent getShutdownIntent() { * @param phoneNumber The phone number. * @return the intent of dial */ - public static Intent getDialIntent(final String phoneNumber) { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)); + public static Intent getDialIntent(@NonNull final String phoneNumber) { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + Uri.encode(phoneNumber))); return getIntent(intent, true); } @@ -322,8 +417,8 @@ public static Intent getDialIntent(final String phoneNumber) { * @return the intent of call */ @RequiresPermission(CALL_PHONE) - public static Intent getCallIntent(final String phoneNumber) { - Intent intent = new Intent("android.intent.action.CALL", Uri.parse("tel:" + phoneNumber)); + public static Intent getCallIntent(@NonNull final String phoneNumber) { + Intent intent = new Intent("android.intent.action.CALL", Uri.parse("tel:" + Uri.encode(phoneNumber))); return getIntent(intent, true); } @@ -334,8 +429,8 @@ public static Intent getCallIntent(final String phoneNumber) { * @param content The content of SMS. * @return the intent of send SMS */ - public static Intent getSendSmsIntent(final String phoneNumber, final String content) { - Uri uri = Uri.parse("smsto:" + phoneNumber); + public static Intent getSendSmsIntent(@NonNull final String phoneNumber, final String content) { + Uri uri = Uri.parse("smsto:" + Uri.encode(phoneNumber)); Intent intent = new Intent(Intent.ACTION_SENDTO, uri); intent.putExtra("sms_body", content); return getIntent(intent, true); @@ -348,10 +443,21 @@ public static Intent getSendSmsIntent(final String phoneNumber, final String con * @return the intent of capture */ public static Intent getCaptureIntent(final Uri outUri) { + return getCaptureIntent(outUri, false); + } + + /** + * Return the intent of capture. + * + * @param outUri The uri of output. + * @param isNewTask True to add flag of new task, false otherwise. + * @return the intent of capture + */ + public static Intent getCaptureIntent(final Uri outUri, final boolean isNewTask) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, outUri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - return getIntent(intent, true); + return getIntent(intent, isNewTask); } private static Intent getIntent(final Intent intent, final boolean isNewTask) { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/JsonUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/JsonUtils.java index 5945b05807..43046adf5a 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/JsonUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/JsonUtils.java @@ -1,7 +1,5 @@ package com.blankj.utilcode.util; -import android.util.Log; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -28,6 +26,27 @@ private JsonUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } + + /** + * Checks if a given input is a JSONObject. + * + * @param input Anything. + * @return true if it is a JSONObject. + */ + public static boolean isJSONObject(final T input) { + return input instanceof JSONObject; + } + + /** + * Checks if a given input is a JSONArray + * + * @param input Anything. + * @return true if it is a JSONArray. + */ + public static boolean isJSONArray(final T input) { + return input instanceof JSONArray; + } + public static boolean getBoolean(final JSONObject jsonObject, final String key) { return getBoolean(jsonObject, key, false); @@ -191,7 +210,7 @@ private static T getValueByType(final JSONObject jsonObject, //noinspection unchecked return (T) ret; } catch (JSONException e) { - Log.e("JsonUtils", "getValueByType: ", e); + e.printStackTrace(); return defaultValue; } } @@ -207,7 +226,7 @@ private static T getValueByType(final String json, try { return getValueByType(new JSONObject(json), key, defaultValue, type); } catch (JSONException e) { - Log.e("JsonUtils", "getValueByType: ", e); + e.printStackTrace(); return defaultValue; } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java index e4c41a1214..e51b3cf891 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java @@ -7,7 +7,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; -import android.support.annotation.NonNull; +import android.os.SystemClock; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -17,7 +17,8 @@ import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.FrameLayout; - +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.lang.reflect.Field; /** @@ -40,7 +41,8 @@ private KeyboardUtils() { * Show the soft input. */ public static void showSoftInput() { - InputMethodManager imm = (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = + (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); if (imm == null) { return; } @@ -50,7 +52,10 @@ public static void showSoftInput() { /** * Show the soft input. */ - public static void showSoftInput(@NonNull Activity activity) { + public static void showSoftInput(@Nullable Activity activity) { + if (activity == null) { + return; + } if (!isSoftInputVisible(activity)) { toggleSoftInput(); } @@ -68,14 +73,16 @@ public static void showSoftInput(@NonNull final View view) { /** * Show the soft input. * - * @param view The view. + * @param view The view. * @param flags Provides additional operating flags. Currently may be - * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} bit set. + * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} bit set. */ public static void showSoftInput(@NonNull final View view, final int flags) { InputMethodManager imm = - (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm == null) return; + (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) { + return; + } view.setFocusable(true); view.setFocusableInTouchMode(true); view.requestFocus(); @@ -83,7 +90,7 @@ public static void showSoftInput(@NonNull final View view, final int flags) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN - || resultCode == InputMethodManager.RESULT_HIDDEN) { + || resultCode == InputMethodManager.RESULT_HIDDEN) { toggleSoftInput(); } } @@ -96,15 +103,30 @@ protected void onReceiveResult(int resultCode, Bundle resultData) { * * @param activity The activity. */ - public static void hideSoftInput(@NonNull final Activity activity) { - View view = activity.getCurrentFocus(); + public static void hideSoftInput(@Nullable final Activity activity) { + if (activity == null) { + return; + } + hideSoftInput(activity.getWindow()); + } + + /** + * Hide the soft input. + * + * @param window The window. + */ + public static void hideSoftInput(@Nullable final Window window) { + if (window == null) { + return; + } + View view = window.getCurrentFocus(); if (view == null) { - View decorView = activity.getWindow().getDecorView(); + View decorView = window.getDecorView(); View focusView = decorView.findViewWithTag("keyboardTagView"); if (focusView == null) { - view = new EditText(activity); + view = new EditText(window.getContext()); view.setTag("keyboardTagView"); - ((ViewGroup) decorView).addView(view, 1, 1); + ((ViewGroup) decorView).addView(view, 0, 0); } else { view = focusView; } @@ -120,8 +142,10 @@ public static void hideSoftInput(@NonNull final Activity activity) { */ public static void hideSoftInput(@NonNull final View view) { InputMethodManager imm = - (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm == null) return; + (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) { + return; + } imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } @@ -132,8 +156,11 @@ public static void hideSoftInput(@NonNull final View view) { * * @param activity The activity. */ - public static void hideSoftInputByToggle(final Activity activity) { - long nowMillis = System.currentTimeMillis(); + public static void hideSoftInputByToggle(@Nullable final Activity activity) { + if (activity == null) { + return; + } + long nowMillis = SystemClock.elapsedRealtime(); long delta = nowMillis - millis; if (Math.abs(delta) > 500 && KeyboardUtils.isSoftInputVisible(activity)) { KeyboardUtils.toggleSoftInput(); @@ -146,8 +173,10 @@ public static void hideSoftInputByToggle(final Activity activity) { */ public static void toggleSoftInput() { InputMethodManager imm = - (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm == null) return; + (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) { + return; + } imm.toggleSoftInput(0, 0); } @@ -167,8 +196,8 @@ private static int getDecorViewInvisibleHeight(@NonNull final Window window) { final View decorView = window.getDecorView(); final Rect outRect = new Rect(); decorView.getWindowVisibleDisplayFrame(outRect); - Log.d("KeyboardUtils", "getDecorViewInvisibleHeight: " - + (decorView.getBottom() - outRect.bottom)); + Log.d("KeyboardUtils", + "getDecorViewInvisibleHeight: " + (decorView.getBottom() - outRect.bottom)); int delta = Math.abs(decorView.getBottom() - outRect.bottom); if (delta <= UtilsBridge.getNavBarHeight() + UtilsBridge.getStatusBarHeight()) { sDecorViewDelta = delta; @@ -184,24 +213,26 @@ private static int getDecorViewInvisibleHeight(@NonNull final Window window) { * @param listener The soft input changed listener. */ public static void registerSoftInputChangedListener(@NonNull final Activity activity, - @NonNull final OnSoftInputChangedListener listener) { + @NonNull + final OnSoftInputChangedListener listener) { registerSoftInputChangedListener(activity.getWindow(), listener); } /** * Register soft input changed listener. * - * @param window The window. + * @param window The window. * @param listener The soft input changed listener. */ public static void registerSoftInputChangedListener(@NonNull final Window window, - @NonNull final OnSoftInputChangedListener listener) { + @NonNull + final OnSoftInputChangedListener listener) { final int flags = window.getAttributes().flags; if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) { window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } final FrameLayout contentView = window.findViewById(android.R.id.content); - final int[] decorViewInvisibleHeightPre = {getDecorViewInvisibleHeight(window)}; + final int[] decorViewInvisibleHeightPre = { getDecorViewInvisibleHeight(window) }; OnGlobalLayoutListener onGlobalLayoutListener = new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { @@ -222,11 +253,16 @@ public void onGlobalLayout() { * @param window The window. */ public static void unregisterSoftInputChangedListener(@NonNull final Window window) { - final FrameLayout contentView = window.findViewById(android.R.id.content); + final View contentView = window.findViewById(android.R.id.content); + if (contentView == null) { + return; + } Object tag = contentView.getTag(TAG_ON_GLOBAL_LAYOUT_LISTENER); if (tag instanceof OnGlobalLayoutListener) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { contentView.getViewTreeObserver().removeOnGlobalLayoutListener((OnGlobalLayoutListener) tag); + //这里会发生内存泄漏 如果不设置为null + contentView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, null); } } } @@ -249,36 +285,35 @@ public static void fixAndroidBug5497(@NonNull final Activity activity) { */ public static void fixAndroidBug5497(@NonNull final Window window) { int softInputMode = window.getAttributes().softInputMode; - window.setSoftInputMode(softInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + window.setSoftInputMode( + softInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); final FrameLayout contentView = window.findViewById(android.R.id.content); final View contentViewChild = contentView.getChildAt(0); final int paddingBottom = contentViewChild.getPaddingBottom(); - final int[] contentViewInvisibleHeightPre5497 = {getContentViewInvisibleHeight(window)}; - contentView.getViewTreeObserver() - .addOnGlobalLayoutListener(new OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - int height = getContentViewInvisibleHeight(window); - if (contentViewInvisibleHeightPre5497[0] != height) { - contentViewChild.setPadding( - contentViewChild.getPaddingLeft(), - contentViewChild.getPaddingTop(), - contentViewChild.getPaddingRight(), - paddingBottom + getDecorViewInvisibleHeight(window) - ); - contentViewInvisibleHeightPre5497[0] = height; - } - } - }); + final int[] contentViewInvisibleHeightPre5497 = { getContentViewInvisibleHeight(window) }; + contentView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + int height = getContentViewInvisibleHeight(window); + if (contentViewInvisibleHeightPre5497[0] != height) { + contentViewChild.setPadding(contentViewChild.getPaddingLeft(), + contentViewChild.getPaddingTop(), contentViewChild.getPaddingRight(), + paddingBottom + getDecorViewInvisibleHeight(window)); + contentViewInvisibleHeightPre5497[0] = height; + } + } + }); } private static int getContentViewInvisibleHeight(final Window window) { final View contentView = window.findViewById(android.R.id.content); - if (contentView == null) return 0; + if (contentView == null) { + return 0; + } final Rect outRect = new Rect(); contentView.getWindowVisibleDisplayFrame(outRect); - Log.d("KeyboardUtils", "getContentViewInvisibleHeight: " - + (contentView.getBottom() - outRect.bottom)); + Log.d("KeyboardUtils", + "getContentViewInvisibleHeight: " + (contentView.getBottom() - outRect.bottom)); int delta = Math.abs(contentView.getBottom() - outRect.bottom); if (delta <= UtilsBridge.getStatusBarHeight() + UtilsBridge.getNavBarHeight()) { return 0; @@ -302,9 +337,12 @@ public static void fixSoftInputLeaks(@NonNull final Activity activity) { */ public static void fixSoftInputLeaks(@NonNull final Window window) { InputMethodManager imm = - (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm == null) return; - String[] leakViews = new String[]{"mLastSrvView", "mCurRootView", "mServedView", "mNextServedView"}; + (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) { + return; + } + String[] leakViews = + new String[] { "mLastSrvView", "mCurRootView", "mServedView", "mNextServedView" }; for (String leakView : leakViews) { try { Field leakViewField = InputMethodManager.class.getDeclaredField(leakView); @@ -312,7 +350,9 @@ public static void fixSoftInputLeaks(@NonNull final Window window) { leakViewField.setAccessible(true); } Object obj = leakViewField.get(imm); - if (!(obj instanceof View)) continue; + if (!(obj instanceof View)) { + continue; + } View view = (View) obj; if (view.getRootView() == window.getDecorView().getRootView()) { leakViewField.set(imm, null); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/LanguageUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/LanguageUtils.java index f73dc14828..ca463854b2 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/LanguageUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/LanguageUtils.java @@ -1,23 +1,18 @@ package com.blankj.utilcode.util; import android.app.Activity; -import android.app.Application; -import android.content.ComponentName; import android.content.Context; -import android.content.ContextWrapper; -import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; import android.text.TextUtils; -import android.util.DisplayMetrics; import android.util.Log; -import java.lang.reflect.Field; import java.util.Locale; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** * * author: Blankj @@ -37,178 +32,287 @@ private LanguageUtils() { /** * Apply the system language. - * It will not restart Activity. u can put it in ur {@link Activity#onCreate(Bundle)}. */ public static void applySystemLanguage() { - if (isAppliedSystemLanguage()) return; - applyLanguage(Resources.getSystem().getConfiguration().locale, "", true, false); - } - - /** - * Apply the system language. - * - * @param activityClz The class of activity will be started after apply system language. - */ - public static void applySystemLanguage(final Class extends Activity> activityClz) { - applyLanguage(Resources.getSystem().getConfiguration().locale, activityClz, true, true); + applySystemLanguage(false); } /** * Apply the system language. * - * @param activityClassName The full class name of activity will be started after apply system language. + * @param isRelaunchApp True to relaunch app, false to recreate all activities. */ - public static void applySystemLanguage(final String activityClassName) { - applyLanguage(Resources.getSystem().getConfiguration().locale, activityClassName, true, true); + public static void applySystemLanguage(final boolean isRelaunchApp) { + applyLanguageReal(null, isRelaunchApp); } /** * Apply the language. - * It will not restart Activity. u can put it in ur {@link Activity#onCreate(Bundle)}. * * @param locale The language of locale. */ public static void applyLanguage(@NonNull final Locale locale) { - if (isAppliedLanguage()) return; - applyLanguage(locale, "", false, false); + applyLanguage(locale, false); } /** * Apply the language. * - * @param locale The language of locale. - * @param activityClz The class of activity will be started after apply system language. - * It will start the launcher activity if the class is null. + * @param locale The language of locale. + * @param isRelaunchApp True to relaunch app, false to recreate all activities. */ public static void applyLanguage(@NonNull final Locale locale, - final Class extends Activity> activityClz) { - applyLanguage(locale, activityClz, false, true); + final boolean isRelaunchApp) { + applyLanguageReal(locale, isRelaunchApp); + } + + private static void applyLanguageReal(final Locale locale, + final boolean isRelaunchApp) { + if (locale == null) { + UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, VALUE_FOLLOW_SYSTEM, true); + } else { + UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, locale2String(locale), true); + } + + Locale destLocal = locale == null ? getLocal(Resources.getSystem().getConfiguration()) : locale; + updateAppContextLanguage(destLocal, new Utils.Consumer() { + @Override + public void accept(Boolean success) { + if (success) { + restart(isRelaunchApp); + } else { + // use relaunch app + UtilsBridge.relaunchApp(); + } + } + }); + } + + private static void restart(final boolean isRelaunchApp) { + if (isRelaunchApp) { + UtilsBridge.relaunchApp(); + } else { + for (Activity activity : UtilsBridge.getActivityList()) { + activity.recreate(); + } + } } /** - * Apply the language. + * Return whether applied the language by {@link LanguageUtils}. * - * @param locale The language of locale. - * @param activityClassName The class of activity will be started after apply system language. - * It will start the launcher activity if the class name is null. + * @return {@code true}: yes
{@code false}: no */ - public static void applyLanguage(@NonNull final Locale locale, - final String activityClassName) { - applyLanguage(locale, activityClassName, false, true); + public static boolean isAppliedLanguage() { + return getAppliedLanguage() != null; } - private static void applyLanguage(@NonNull final Locale locale, - final Class extends Activity> activityClz, - final boolean isFollowSystem, - final boolean isNeedStartActivity) { - if (activityClz == null) { - applyLanguage(locale, "", isFollowSystem, isNeedStartActivity); - return; + /** + * Return whether applied the language by {@link LanguageUtils}. + * + * @param locale The locale. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppliedLanguage(@NonNull Locale locale) { + Locale appliedLocale = getAppliedLanguage(); + if (appliedLocale == null) { + return false; } - applyLanguage(locale, activityClz.getName(), isFollowSystem, isNeedStartActivity); + return isSameLocale(locale, appliedLocale); } - private static void applyLanguage(@NonNull final Locale locale, - final String activityClassName, - final boolean isFollowSystem, - final boolean isNeedStartActivity) { - if (isFollowSystem) { - UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, VALUE_FOLLOW_SYSTEM); - } else { - String localLanguage = locale.getLanguage(); - String localCountry = locale.getCountry(); - UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, localLanguage + "$" + localCountry); + /** + * Return the applied locale. + * + * @return the applied locale + */ + public static Locale getAppliedLanguage() { + final String spLocaleStr = UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE); + if (TextUtils.isEmpty(spLocaleStr) || VALUE_FOLLOW_SYSTEM.equals(spLocaleStr)) { + return null; } + return string2Locale(spLocaleStr); + } - updateLanguage(Utils.getApp(), locale); + /** + * Return the locale of context. + * + * @return the locale of context + */ + public static Locale getContextLanguage(Context context) { + return getLocal(context.getResources().getConfiguration()); + } - if (isNeedStartActivity) { - Intent intent = new Intent(); - String realActivityClassName = TextUtils.isEmpty(activityClassName) ? UtilsBridge.getLauncherActivity() : activityClassName; - intent.setComponent(new ComponentName(Utils.getApp(), realActivityClassName)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK); - Utils.getApp().startActivity(intent); - } + /** + * Return the locale of applicationContext. + * + * @return the locale of applicationContext + */ + public static Locale getAppContextLanguage() { + return getContextLanguage(Utils.getApp()); } /** - * Return whether applied the system language by {@link LanguageUtils}. + * Return the locale of system * - * @return {@code true}: yes
{@code false}: no + * @return the locale of system */ - public static boolean isAppliedSystemLanguage() { - return VALUE_FOLLOW_SYSTEM.equals(UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE)); + public static Locale getSystemLanguage() { + return getLocal(Resources.getSystem().getConfiguration()); } /** - * Return whether applied the language by {@link LanguageUtils}. + * Update the locale of applicationContext. * - * @return {@code true}: yes
{@code false}: no + * @param destLocale The dest locale. + * @param consumer The consumer. */ - public static boolean isAppliedLanguage() { - return !TextUtils.isEmpty(UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE)); + public static void updateAppContextLanguage(@NonNull Locale destLocale, @Nullable Utils.Consumerconsumer) { + pollCheckAppContextLocal(destLocale, 0, consumer); + } + + static void pollCheckAppContextLocal(final Locale destLocale, final int index, final Utils.Consumer consumer) { + Resources appResources = Utils.getApp().getResources(); + Configuration appConfig = appResources.getConfiguration(); + Locale appLocal = getLocal(appConfig); + + setLocal(appConfig, destLocale); + + Utils.getApp().getResources().updateConfiguration(appConfig, appResources.getDisplayMetrics()); + + if (consumer == null) return; + + if (isSameLocale(appLocal, destLocale)) { + consumer.accept(true); + } else { + if (index < 20) { + UtilsBridge.runOnUiThreadDelayed(new Runnable() { + @Override + public void run() { + pollCheckAppContextLocal(destLocale, index + 1, consumer); + } + }, 16); + return; + } + Log.e("LanguageUtils", "appLocal didn't update."); + consumer.accept(false); + } } /** - * Return the locale. + * If applyLanguage not work, try to call it in {@link Activity#attachBaseContext(Context)}. * - * @return the locale + * @param context The baseContext. + * @return the context with language */ - public static Locale getCurrentLocale() { - return Utils.getApp().getResources().getConfiguration().locale; + public static Context attachBaseContext(Context context) { + String spLocaleStr = UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE); + if (TextUtils.isEmpty(spLocaleStr) || VALUE_FOLLOW_SYSTEM.equals(spLocaleStr)) { + return context; + } + + Locale settingsLocale = string2Locale(spLocaleStr); + if (settingsLocale == null) return context; + + Resources resources = context.getResources(); + Configuration config = resources.getConfiguration(); + + setLocal(config, settingsLocale); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return context.createConfigurationContext(config); + } else { + resources.updateConfiguration(config, resources.getDisplayMetrics()); + return context; + } } - static void applyLanguage(@NonNull final Activity activity) { - final String spLocale = UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE); + static void applyLanguage(final Activity activity) { + String spLocale = UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE); if (TextUtils.isEmpty(spLocale)) { return; } + Locale destLocal; if (VALUE_FOLLOW_SYSTEM.equals(spLocale)) { - Locale sysLocale = Resources.getSystem().getConfiguration().locale; - updateLanguage(Utils.getApp(), sysLocale); - updateLanguage(activity, sysLocale); - return; + destLocal = getLocal(Resources.getSystem().getConfiguration()); + } else { + destLocal = string2Locale(spLocale); } - String[] language_country = spLocale.split("\\$"); - if (language_country.length != 2) { - Log.e("LanguageUtils", "The string of " + spLocale + " is not in the correct format."); - return; - } + if (destLocal == null) return; - Locale settingLocale = new Locale(language_country[0], language_country[1]); - updateLanguage(Utils.getApp(), settingLocale); - updateLanguage(activity, settingLocale); + updateConfiguration(activity, destLocal); + updateConfiguration(Utils.getApp(), destLocal); } - private static void updateLanguage(final Context context, Locale locale) { + private static void updateConfiguration(Context context, Locale destLocal) { Resources resources = context.getResources(); Configuration config = resources.getConfiguration(); - Locale contextLocale = config.locale; - if (isSameLocale(contextLocale, locale)) { - return; + setLocal(config, destLocal); + resources.updateConfiguration(config, resources.getDisplayMetrics()); + } + + private static String locale2String(Locale locale) { + String localLanguage = locale.getLanguage(); // this may be empty + String localCountry = locale.getCountry(); // this may be empty + return localLanguage + "$" + localCountry; + } + + private static Locale string2Locale(String str) { + Locale locale = string2LocaleReal(str); + if (locale == null) { + Log.e("LanguageUtils", "The string of " + str + " is not in the correct format."); + UtilsBridge.getSpUtils4Utils().remove(KEY_LOCALE); } - DisplayMetrics dm = resources.getDisplayMetrics(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - config.setLocale(locale); - if (context instanceof Application) { - Context newContext = context.createConfigurationContext(config); - try { - //noinspection JavaReflectionMemberAccess - Field mBaseField = ContextWrapper.class.getDeclaredField("mBase"); - mBaseField.setAccessible(true); - mBaseField.set(context, newContext); - } catch (Exception ignored) {/**/} + return locale; + } + + private static Locale string2LocaleReal(String str) { + if (!isRightFormatLocalStr(str)) { + return null; + } + + try { + int splitIndex = str.indexOf("$"); + return new Locale(str.substring(0, splitIndex), str.substring(splitIndex + 1)); + } catch (Exception ignore) { + return null; + } + } + + private static boolean isRightFormatLocalStr(String localStr) { + char[] chars = localStr.toCharArray(); + int count = 0; + for (char c : chars) { + if (c == '$') { + if (count >= 1) { + return false; + } + ++count; } + } + return count == 1; + } + + private static boolean isSameLocale(Locale l0, Locale l1) { + return UtilsBridge.equals(l1.getLanguage(), l0.getLanguage()) + && UtilsBridge.equals(l1.getCountry(), l0.getCountry()); + } + + private static Locale getLocal(Configuration configuration) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return configuration.getLocales().get(0); } else { - config.locale = locale; + return configuration.locale; } - resources.updateConfiguration(config, dm); } - private static boolean isSameLocale(Locale locale, Locale contextLocale) { - return UtilsBridge.equals(contextLocale.getLanguage(), locale.getLanguage()) - && UtilsBridge.equals(contextLocale.getCountry(), locale.getCountry()); + private static void setLocal(Configuration configuration, Locale locale) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + configuration.setLocale(locale); + } else { + configuration.locale = locale; + } } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/LogUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/LogUtils.java index 040a3545d0..128e2b8de6 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/LogUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/LogUtils.java @@ -7,10 +7,6 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.IntDef; -import android.support.annotation.IntRange; -import android.support.annotation.RequiresApi; -import android.support.v4.util.SimpleArrayMap; import android.util.Log; import org.json.JSONArray; @@ -36,6 +32,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -49,6 +46,11 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import androidx.annotation.IntDef; +import androidx.annotation.IntRange; +import androidx.annotation.RequiresApi; +import androidx.collection.SimpleArrayMap; + /** * * author: Blankj @@ -228,6 +230,10 @@ public void run() { } } + public static String getCurrentLogFilePath() { + return getCurrentLogFilePath(new Date()); + } + public static ListgetLogFiles() { String dir = CONFIG.getDir(); File logDir = new File(dir); @@ -379,16 +385,16 @@ private static void print2Console(final int type, private static void printBorder(final int type, final String tag, boolean isTop) { if (CONFIG.isLogBorderSwitch()) { - Log.println(type, tag, isTop ? TOP_BORDER : BOTTOM_BORDER); + print2Console(type, tag, isTop ? TOP_BORDER : BOTTOM_BORDER); } } private static void printHead(final int type, final String tag, final String[] head) { if (head != null) { for (String aHead : head) { - Log.println(type, tag, CONFIG.isLogBorderSwitch() ? LEFT_BORDER + aHead : aHead); + print2Console(type, tag, CONFIG.isLogBorderSwitch() ? LEFT_BORDER + aHead : aHead); } - if (CONFIG.isLogBorderSwitch()) Log.println(type, tag, MIDDLE_BORDER); + if (CONFIG.isLogBorderSwitch()) print2Console(type, tag, MIDDLE_BORDER); } } @@ -411,13 +417,13 @@ private static void printMsg(final int type, final String tag, final String msg) private static void printSubMsg(final int type, final String tag, final String msg) { if (!CONFIG.isLogBorderSwitch()) { - Log.println(type, tag, msg); + print2Console(type, tag, msg); return; } StringBuilder sb = new StringBuilder(); String[] lines = msg.split(LINE_SEP); for (String line : lines) { - Log.println(type, tag, LEFT_BORDER + line); + print2Console(type, tag, LEFT_BORDER + line); } } @@ -456,56 +462,70 @@ private static void printSingleTagMsg(final int type, final String tag, final St int countOfSub = CONFIG.isLogBorderSwitch() ? (len - BOTTOM_BORDER.length()) / MAX_LEN : len / MAX_LEN; if (countOfSub > 0) { if (CONFIG.isLogBorderSwitch()) { - Log.println(type, tag, msg.substring(0, MAX_LEN) + LINE_SEP + BOTTOM_BORDER); + print2Console(type, tag, msg.substring(0, MAX_LEN) + LINE_SEP + BOTTOM_BORDER); int index = MAX_LEN; for (int i = 1; i < countOfSub; i++) { - Log.println(type, tag, PLACEHOLDER + LINE_SEP + TOP_BORDER + LINE_SEP + print2Console(type, tag, PLACEHOLDER + LINE_SEP + TOP_BORDER + LINE_SEP + LEFT_BORDER + msg.substring(index, index + MAX_LEN) + LINE_SEP + BOTTOM_BORDER); index += MAX_LEN; } if (index != len - BOTTOM_BORDER.length()) { - Log.println(type, tag, PLACEHOLDER + LINE_SEP + TOP_BORDER + LINE_SEP + print2Console(type, tag, PLACEHOLDER + LINE_SEP + TOP_BORDER + LINE_SEP + LEFT_BORDER + msg.substring(index, len)); } } else { - Log.println(type, tag, msg.substring(0, MAX_LEN)); + print2Console(type, tag, msg.substring(0, MAX_LEN)); int index = MAX_LEN; for (int i = 1; i < countOfSub; i++) { - Log.println(type, tag, + print2Console(type, tag, PLACEHOLDER + LINE_SEP + msg.substring(index, index + MAX_LEN)); index += MAX_LEN; } if (index != len) { - Log.println(type, tag, PLACEHOLDER + LINE_SEP + msg.substring(index, len)); + print2Console(type, tag, PLACEHOLDER + LINE_SEP + msg.substring(index, len)); } } } else { - Log.println(type, tag, msg); + print2Console(type, tag, msg); + } + } + + private static void print2Console(int type, String tag, String msg) { + Log.println(type, tag, msg); + if (CONFIG.mOnConsoleOutputListener != null) { + CONFIG.mOnConsoleOutputListener.onConsoleOutput(type, tag, msg); } } private static void print2File(final int type, final String tag, final String msg) { - String format = getSdf().format(new Date()); + Date d = new Date(); + String format = getSdf().format(d); String date = format.substring(0, 10); - String time = format.substring(11); - final String fullPath = - CONFIG.getDir() + CONFIG.getFilePrefix() + "_" - + date + "_" + - CONFIG.getProcessName() + CONFIG.getFileExtension(); - if (!createOrExistsFile(fullPath, date)) { - Log.e("LogUtils", "create " + fullPath + " failed!"); + String currentLogFilePath = getCurrentLogFilePath(d); + if (!createOrExistsFile(currentLogFilePath, date)) { + Log.e("LogUtils", "create " + currentLogFilePath + " failed!"); return; } + String time = format.substring(11); final String content = time + T[type - V] + "/" + tag + msg + LINE_SEP; - input2File(fullPath, content); + input2File(currentLogFilePath, content); } + private static String getCurrentLogFilePath(Date d) { + String format = getSdf().format(d); + String date = format.substring(0, 10); + return CONFIG.getDir() + CONFIG.getFilePrefix() + "_" + + date + "_" + + CONFIG.getProcessName() + CONFIG.getFileExtension(); + } + + private static SimpleDateFormat getSdf() { if (simpleDateFormat == null) { simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd HH:mm:ss.SSS ", Locale.getDefault()); @@ -579,16 +599,8 @@ private static String findDate(String str) { } private static void printDeviceInfo(final String filePath, final String date) { - final String head = "************* Log Head ****************" + - "\nDate of Log : " + date + - "\nDevice Manufacturer: " + Build.MANUFACTURER + - "\nDevice Model : " + Build.MODEL + - "\nAndroid Version : " + Build.VERSION.RELEASE + - "\nAndroid SDK : " + Build.VERSION.SDK_INT + - "\nApp VersionName : " + UtilsBridge.getAppVersionName() + - "\nApp VersionCode : " + UtilsBridge.getAppVersionCode() + - "\n************* Log Head ****************\n\n"; - input2File(filePath, head); + CONFIG.mFileHead.addFirst("Date of Log", date); + input2File(filePath, CONFIG.mFileHead.toString()); } private static void input2File(final String filePath, final String input) { @@ -597,28 +609,34 @@ private static void input2File(final String filePath, final String input) { } else { CONFIG.mFileWriter.write(filePath, input); } + if (CONFIG.mOnFileOutputListener != null) { + CONFIG.mOnFileOutputListener.onFileOutput(filePath, input); + } } public static final class Config { - private String mDefaultDir;// The default storage directory of log. - private String mDir; // The storage directory of log. - private String mFilePrefix = "util";// The file prefix of log. - private String mFileExtension = ".txt";// The file extension of log. - private boolean mLogSwitch = true; // The switch of log. - private boolean mLog2ConsoleSwitch = true; // The logcat's switch of log. - private String mGlobalTag = ""; // The global tag of log. - private boolean mTagIsSpace = true; // The global tag is space. - private boolean mLogHeadSwitch = true; // The head's switch of log. - private boolean mLog2FileSwitch = false; // The file's switch of log. - private boolean mLogBorderSwitch = true; // The border's switch of log. - private boolean mSingleTagSwitch = true; // The single tag of log. - private int mConsoleFilter = V; // The console's filter of log. - private int mFileFilter = V; // The file's filter of log. - private int mStackDeep = 1; // The stack's deep of log. - private int mStackOffset = 0; // The stack's offset of log. - private int mSaveDays = -1; // The save days of log. - private String mProcessName = UtilsBridge.getCurrentProcessName(); - private IFileWriter mFileWriter; + private String mDefaultDir; // The default storage directory of log. + private String mDir; // The storage directory of log. + private String mFilePrefix = "util";// The file prefix of log. + private String mFileExtension = ".txt";// The file extension of log. + private boolean mLogSwitch = true; // The switch of log. + private boolean mLog2ConsoleSwitch = true; // The logcat's switch of log. + private String mGlobalTag = ""; // The global tag of log. + private boolean mTagIsSpace = true; // The global tag is space. + private boolean mLogHeadSwitch = true; // The head's switch of log. + private boolean mLog2FileSwitch = false; // The file's switch of log. + private boolean mLogBorderSwitch = true; // The border's switch of log. + private boolean mSingleTagSwitch = true; // The single tag of log. + private int mConsoleFilter = V; // The console's filter of log. + private int mFileFilter = V; // The file's filter of log. + private int mStackDeep = 1; // The stack's deep of log. + private int mStackOffset = 0; // The stack's offset of log. + private int mSaveDays = -1; // The save days of log. + private String mProcessName = UtilsBridge.getCurrentProcessName(); + private IFileWriter mFileWriter; + private OnConsoleOutputListener mOnConsoleOutputListener; + private OnFileOutputListener mOnFileOutputListener; + private UtilsBridge.FileHead mFileHead = new UtilsBridge.FileHead("Log"); private Config() { if (UtilsBridge.isSDCardEnableByEnvironment() @@ -743,6 +761,26 @@ public final Config setFileWriter(final IFileWriter fileWriter) { return this; } + public final Config setOnConsoleOutputListener(final OnConsoleOutputListener listener) { + mOnConsoleOutputListener = listener; + return this; + } + + public final Config setOnFileOutputListener(final OnFileOutputListener listener) { + mOnFileOutputListener = listener; + return this; + } + + public final Config addFileExtraHead(final Map fileExtraHead) { + mFileHead.append(fileExtraHead); + return this; + } + + public final Config addFileExtraHead(final String key, final String value) { + mFileHead.append(key, value); + return this; + } + public final String getProcessName() { if (mProcessName == null) return ""; return mProcessName.replace(":", "_"); @@ -813,24 +851,36 @@ public final int getSaveDays() { return mSaveDays; } + public final boolean haveSetOnConsoleOutputListener() { + return mOnConsoleOutputListener != null; + } + + public final boolean haveSetOnFileOutputListener() { + return mOnFileOutputListener != null; + } + @Override public String toString() { return "process: " + getProcessName() - + LINE_SEP + "switch: " + isLogSwitch() - + LINE_SEP + "console: " + isLog2ConsoleSwitch() - + LINE_SEP + "tag: " + getGlobalTag() - + LINE_SEP + "head: " + isLogHeadSwitch() - + LINE_SEP + "file: " + isLog2FileSwitch() + + LINE_SEP + "logSwitch: " + isLogSwitch() + + LINE_SEP + "consoleSwitch: " + isLog2ConsoleSwitch() + + LINE_SEP + "tag: " + (getGlobalTag().equals("") ? "null" : getGlobalTag()) + + LINE_SEP + "headSwitch: " + isLogHeadSwitch() + + LINE_SEP + "fileSwitch: " + isLog2FileSwitch() + LINE_SEP + "dir: " + getDir() + LINE_SEP + "filePrefix: " + getFilePrefix() - + LINE_SEP + "border: " + isLogBorderSwitch() - + LINE_SEP + "singleTag: " + isSingleTagSwitch() + + LINE_SEP + "borderSwitch: " + isLogBorderSwitch() + + LINE_SEP + "singleTagSwitch: " + isSingleTagSwitch() + LINE_SEP + "consoleFilter: " + getConsoleFilter() + LINE_SEP + "fileFilter: " + getFileFilter() + LINE_SEP + "stackDeep: " + getStackDeep() + LINE_SEP + "stackOffset: " + getStackOffset() + LINE_SEP + "saveDays: " + getSaveDays() - + LINE_SEP + "formatter: " + I_FORMATTER_MAP; + + LINE_SEP + "formatter: " + I_FORMATTER_MAP + + LINE_SEP + "fileWriter: " + mFileWriter + + LINE_SEP + "onConsoleOutputListener: " + mOnConsoleOutputListener + + LINE_SEP + "onFileOutputListener: " + mOnFileOutputListener + + LINE_SEP + "fileExtraHeader: " + mFileHead.getAppended(); } } @@ -842,6 +892,14 @@ public interface IFileWriter { void write(String file, String content); } + public interface OnConsoleOutputListener { + void onConsoleOutput(@TYPE int type, String tag, String content); + } + + public interface OnFileOutputListener { + void onFileOutput(String filePath, String content); + } + private final static class TagHead { String tag; String[] consoleHead; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/MessengerUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/MessengerUtils.java index d172079785..5b246d7c47 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/MessengerUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/MessengerUtils.java @@ -1,22 +1,29 @@ package com.blankj.utilcode.util; import android.annotation.SuppressLint; +import android.app.Notification; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; @@ -48,8 +55,7 @@ public static void register() { Log.i("MessengerUtils", "Server service is running."); return; } - Intent intent = new Intent(Utils.getApp(), ServerService.class); - Utils.getApp().startService(intent); + startServiceCompat(new Intent(Utils.getApp(), ServerService.class)); return; } if (sLocalClient == null) { @@ -92,12 +98,14 @@ public static void register(final String pkgName) { } public static void unregister(final String pkgName) { - if (sClientMap.containsKey(pkgName)) { - Client client = sClientMap.get(pkgName); - sClientMap.remove(pkgName); - client.unbind(); - } else { + if (!sClientMap.containsKey(pkgName)) { Log.i("MessengerUtils", "unregister: client didn't register: " + pkgName); + return; + } + Client client = sClientMap.get(pkgName); + sClientMap.remove(pkgName); + if (client != null) { + client.unbind(); } } @@ -116,13 +124,26 @@ public static void post(@NonNull String key, @NonNull Bundle data) { } else { Intent intent = new Intent(Utils.getApp(), ServerService.class); intent.putExtras(data); - Utils.getApp().startService(intent); + startServiceCompat(intent); } for (Client client : sClientMap.values()) { client.sendMsg2Server(data); } } + private static void startServiceCompat(Intent intent) { + try { + intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Utils.getApp().startForegroundService(intent); + } else { + Utils.getApp().startService(intent); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + static class Client { String mPkgName; @@ -133,13 +154,12 @@ static class Client { @Override public void handleMessage(Message msg) { Bundle data = msg.getData(); - if (data != null) { - String key = data.getString(KEY_STRING); - if (key != null) { - MessageCallback callback = subscribers.get(key); - if (callback != null) { - callback.messageCall(data); - } + data.setClassLoader(MessengerUtils.class.getClassLoader()); + String key = data.getString(KEY_STRING); + if (key != null) { + MessageCallback callback = subscribers.get(key); + if (callback != null) { + callback.messageCall(data); } } } @@ -153,11 +173,12 @@ public void onServiceConnected(ComponentName name, IBinder service) { mServer = new Messenger(service); int key = UtilsBridge.getCurrentProcessName().hashCode(); Message msg = Message.obtain(mReceiveServeMsgHandler, WHAT_SUBSCRIBE, key, 0); + msg.getData().setClassLoader(MessengerUtils.class.getClassLoader()); msg.replyTo = mClient; try { mServer.send(msg); } catch (RemoteException e) { - Log.e("MessengerUtils", "onServiceConnected: ", e); + e.printStackTrace(); } sendCachedMsg2Server(); } @@ -203,7 +224,7 @@ void unbind() { try { mServer.send(msg); } catch (RemoteException e) { - Log.e("MessengerUtils", "unbind: ", e); + e.printStackTrace(); } try { Utils.getApp().unbindService(mConn); @@ -233,13 +254,14 @@ private void sendCachedMsg2Server() { private boolean send2Server(Bundle bundle) { Message msg = Message.obtain(mReceiveServeMsgHandler, WHAT_SEND); + bundle.setClassLoader(MessengerUtils.class.getClassLoader()); msg.setData(bundle); msg.replyTo = mClient; try { mServer.send(msg); return true; } catch (RemoteException e) { - Log.e("MessengerUtils", "send2Server: ", e); + e.printStackTrace(); return false; } } @@ -280,6 +302,12 @@ public IBinder onBind(Intent intent) { @Override public int onStartCommand(Intent intent, int flags, int startId) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Notification notification = UtilsBridge.getNotification( + NotificationUtils.ChannelConfig.DEFAULT_CHANNEL_CONFIG, null + ); + startForeground(1, notification); + } if (intent != null) { Bundle extras = intent.getExtras(); if (extras != null) { @@ -294,15 +322,17 @@ public int onStartCommand(Intent intent, int flags, int startId) { } private void sendMsg2Client(final Message msg) { + final Message obtain = Message.obtain(msg); //Copy the original for (Messenger client : mClientMap.values()) { try { if (client != null) { - client.send(msg); + client.send(Message.obtain(obtain)); } } catch (RemoteException e) { e.printStackTrace(); } } + obtain.recycle(); //Recycled copy } private void consumeServerProcessCallback(final Message msg) { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java index 6f6cf85b80..0ff8fa8798 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java @@ -8,7 +8,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * @@ -118,7 +118,7 @@ public static String getMetaDataInService(@NonNull final Class extends Service */ public static String getMetaDataInReceiver(@NonNull final BroadcastReceiver receiver, @NonNull final String key) { - return getMetaDataInReceiver(receiver, key); + return getMetaDataInReceiver(receiver.getClass(), key); } /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/NetworkUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/NetworkUtils.java index 20145fe440..e73b6487db 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/NetworkUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/NetworkUtils.java @@ -6,15 +6,18 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresPermission; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.format.Formatter; -import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresPermission; import java.lang.reflect.Method; import java.net.InetAddress; @@ -22,12 +25,18 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CopyOnWriteArraySet; +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.ACCESS_WIFI_STATE; import static android.Manifest.permission.CHANGE_WIFI_STATE; @@ -226,8 +235,8 @@ public static boolean isAvailableByDns(final String domain) { return inetAddress != null; } catch (UnknownHostException e) { e.printStackTrace(); + return false; } - return false; } /** @@ -250,10 +259,38 @@ public static boolean getMobileDataEnabled() { return (boolean) getMobileDataEnabledMethod.invoke(tm); } } catch (Exception e) { - Log.e("NetworkUtils", "getMobileDataEnabled: ", e); + e.printStackTrace(); } return false; } + + /** + * Returns true if device is connecting to the internet via a proxy, works for both Wi-Fi and Mobile Data. + * + * @return true if using proxy to connect to the internet. + */ + public static boolean isBehindProxy(){ + return !(System.getProperty("http.proxyHost") == null || System.getProperty("http.proxyPort") == null); + } + + /** + * Returns true if device is connecting to the internet via a VPN. + * + * @return true if using VPN to conncet to the internet. + */ + public static boolean isUsingVPN(){ + ConnectivityManager cm = (ConnectivityManager) com.blankj.utilcode.util.Utils.getApp().getSystemService(Context.CONNECTIVITY_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + return cm.getNetworkInfo(ConnectivityManager.TYPE_VPN).isConnectedOrConnecting(); + } else { + return cm.getNetworkInfo(NetworkCapabilities.TRANSPORT_VPN).isConnectedOrConnecting(); + } + } + + + + + /** * Return whether using mobile data. @@ -660,11 +697,33 @@ public static String getServerAddressByWifi() { return Formatter.formatIpAddress(wm.getDhcpInfo().serverAddress); } + /** + * Return the ssid. + * + * @return the ssid. + */ + @RequiresPermission(ACCESS_WIFI_STATE) + public static String getSSID() { + WifiManager wm = (WifiManager) Utils.getApp().getApplicationContext().getSystemService(WIFI_SERVICE); + if (wm == null) return ""; + WifiInfo wi = wm.getConnectionInfo(); + if (wi == null) return ""; + String ssid = wi.getSSID(); + if (TextUtils.isEmpty(ssid)) { + return ""; + } + if (ssid.length() > 2 && ssid.charAt(0) == '"' && ssid.charAt(ssid.length() - 1) == '"') { + return ssid.substring(1, ssid.length() - 1); + } + return ssid; + } + /** * Register the status of network changed listener. * * @param listener The status of network changed listener */ + @RequiresPermission(ACCESS_NETWORK_STATE) public static void registerNetworkStatusChangedListener(final OnNetworkStatusChangedListener listener) { NetworkChangedReceiver.getInstance().registerListener(listener); } @@ -688,6 +747,123 @@ public static void unregisterNetworkStatusChangedListener(final OnNetworkStatusC NetworkChangedReceiver.getInstance().unregisterListener(listener); } + @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_COARSE_LOCATION}) + public static WifiScanResults getWifiScanResult() { + WifiScanResults result = new WifiScanResults(); + if (!getWifiEnabled()) return result; + @SuppressLint("WifiManagerLeak") + WifiManager wm = (WifiManager) Utils.getApp().getSystemService(WIFI_SERVICE); + //noinspection ConstantConditions + Listresults = wm.getScanResults(); + if (results != null) { + result.setAllResults(results); + } + return result; + } + + private static final long SCAN_PERIOD_MILLIS = 3000; + private static final Set > SCAN_RESULT_CONSUMERS = new CopyOnWriteArraySet<>(); + private static Timer sScanWifiTimer; + private static WifiScanResults sPreWifiScanResults; + + @RequiresPermission(allOf = {ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, ACCESS_COARSE_LOCATION}) + public static void addOnWifiChangedConsumer(final Utils.Consumer consumer) { + if (consumer == null) return; + UtilsBridge.runOnUiThread(new Runnable() { + @Override + public void run() { + if (SCAN_RESULT_CONSUMERS.isEmpty()) { + SCAN_RESULT_CONSUMERS.add(consumer); + startScanWifi(); + return; + } + consumer.accept(sPreWifiScanResults); + SCAN_RESULT_CONSUMERS.add(consumer); + } + }); + } + + private static void startScanWifi() { + sPreWifiScanResults = new WifiScanResults(); + sScanWifiTimer = new Timer(); + sScanWifiTimer.schedule(new TimerTask() { + @RequiresPermission(allOf = {ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, ACCESS_COARSE_LOCATION}) + @Override + public void run() { + startScanWifiIfEnabled(); + WifiScanResults scanResults = getWifiScanResult(); + if (isSameScanResults(sPreWifiScanResults.allResults, scanResults.allResults)) { + return; + } + sPreWifiScanResults = scanResults; + UtilsBridge.runOnUiThread(new Runnable() { + @Override + public void run() { + for (Utils.Consumer consumer : SCAN_RESULT_CONSUMERS) { + consumer.accept(sPreWifiScanResults); + } + } + }); + } + }, 0, SCAN_PERIOD_MILLIS); + } + + @RequiresPermission(allOf = {ACCESS_WIFI_STATE, CHANGE_WIFI_STATE}) + private static void startScanWifiIfEnabled() { + if (!getWifiEnabled()) return; + @SuppressLint("WifiManagerLeak") + WifiManager wm = (WifiManager) Utils.getApp().getSystemService(WIFI_SERVICE); + //noinspection ConstantConditions + wm.startScan(); + } + + public static void removeOnWifiChangedConsumer(final Utils.Consumer consumer) { + if (consumer == null) return; + UtilsBridge.runOnUiThread(new Runnable() { + @Override + public void run() { + SCAN_RESULT_CONSUMERS.remove(consumer); + if (SCAN_RESULT_CONSUMERS.isEmpty()) { + stopScanWifi(); + } + } + }); + } + + private static void stopScanWifi() { + if (sScanWifiTimer != null) { + sScanWifiTimer.cancel(); + sScanWifiTimer = null; + } + } + + private static boolean isSameScanResults(List l1, List l2) { + if (l1 == null && l2 == null) { + return true; + } + if (l1 == null || l2 == null) { + return false; + } + if (l1.size() != l2.size()) { + return false; + } + for (int i = 0; i < l1.size(); i++) { + ScanResult r1 = l1.get(i); + ScanResult r2 = l2.get(i); + if (!isSameScanResultContent(r1, r2)) { + return false; + } + } + return true; + } + + private static boolean isSameScanResultContent(ScanResult r1, ScanResult r2) { + return r1 != null && r2 != null && UtilsBridge.equals(r1.BSSID, r2.BSSID) + && UtilsBridge.equals(r1.SSID, r2.SSID) + && UtilsBridge.equals(r1.capabilities, r2.capabilities) + && r1.level == r2.level; + } + public static final class NetworkChangedReceiver extends BroadcastReceiver { private static NetworkChangedReceiver getInstance() { @@ -697,11 +873,12 @@ private static NetworkChangedReceiver getInstance() { private NetworkType mType; private Set mListeners = new HashSet<>(); + @RequiresPermission(ACCESS_NETWORK_STATE) void registerListener(final OnNetworkStatusChangedListener listener) { if (listener == null) return; UtilsBridge.runOnUiThread(new Runnable() { - @SuppressLint("MissingPermission") @Override + @RequiresPermission(ACCESS_NETWORK_STATE) public void run() { int preSize = mListeners.size(); mListeners.add(listener); @@ -733,13 +910,13 @@ public void run() { }); } - @SuppressLint("MissingPermission") @Override public void onReceive(Context context, Intent intent) { if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { // debouncing UtilsBridge.runOnUiThreadDelayed(new Runnable() { @Override + @RequiresPermission(ACCESS_NETWORK_STATE) public void run() { NetworkType networkType = NetworkUtils.getNetworkType(); if (mType == networkType) return; @@ -842,4 +1019,45 @@ public interface OnNetworkStatusChangedListener { void onConnected(NetworkType networkType); } + + public static final class WifiScanResults { + + private List allResults = new ArrayList<>(); + private List filterResults = new ArrayList<>(); + + public WifiScanResults() { + } + + public List getAllResults() { + return allResults; + } + + public List getFilterResults() { + return filterResults; + } + + public void setAllResults(List allResults) { + this.allResults = allResults; + filterResults = filterScanResult(allResults); + } + + private static List filterScanResult(final List results) { + if (results == null || results.isEmpty()) { + return new ArrayList<>(); + } + LinkedHashMap map = new LinkedHashMap<>(results.size()); + for (ScanResult result : results) { + if (TextUtils.isEmpty(result.SSID)) { + continue; + } + ScanResult resultInMap = map.get(result.SSID); + if (resultInMap != null && resultInMap.level >= result.level) { + continue; + } + map.put(result.SSID, result); + } + return new ArrayList<>(map.values()); + } + + } } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/NotificationUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/NotificationUtils.java index 42a97f5066..cea486d094 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/NotificationUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/NotificationUtils.java @@ -8,15 +8,16 @@ import android.media.AudioAttributes; import android.net.Uri; import android.os.Build; -import android.support.annotation.IntDef; -import android.support.annotation.RequiresPermission; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; +import androidx.annotation.IntDef; +import androidx.annotation.RequiresPermission; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + import static android.Manifest.permission.EXPAND_STATUS_BAR; /** @@ -91,21 +92,26 @@ public static void notify(int id, ChannelConfig channelConfig, Utils.Consumer consumer) { + NotificationManagerCompat.from(Utils.getApp()).notify(tag, id, getNotification(channelConfig, consumer)); + } + + + public static Notification getNotification(ChannelConfig channelConfig, Utils.Consumer consumer) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager nm = (NotificationManager) Utils.getApp().getSystemService(Context.NOTIFICATION_SERVICE); //noinspection ConstantConditions nm.createNotificationChannel(channelConfig.getNotificationChannel()); } - NotificationManagerCompat nmc = NotificationManagerCompat.from(Utils.getApp()); - NotificationCompat.Builder builder = new NotificationCompat.Builder(Utils.getApp()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(channelConfig.mNotificationChannel.getId()); } - consumer.accept(builder); + if (consumer != null) { + consumer.accept(builder); + } - nmc.notify(tag, id, builder.build()); + return builder.build(); } /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ObjectUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ObjectUtils.java index d20a32574a..b835448861 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ObjectUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ObjectUtils.java @@ -1,10 +1,6 @@ package com.blankj.utilcode.util; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; -import android.support.v4.util.LongSparseArray; -import android.support.v4.util.SimpleArrayMap; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; @@ -16,6 +12,11 @@ import java.util.Comparator; import java.util.Map; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.collection.LongSparseArray; +import androidx.collection.SimpleArrayMap; + /** * * author: Blankj diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/PermissionUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/PermissionUtils.java index 5b411ec370..a4e2f73e57 100755 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/PermissionUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/PermissionUtils.java @@ -8,15 +8,12 @@ import android.os.Build; import android.os.Bundle; import android.provider.Settings; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.support.v4.content.ContextCompat; import android.util.Log; +import android.util.Pair; import android.view.MotionEvent; import android.view.WindowManager; import com.blankj.utilcode.constant.PermissionConstants; -import com.blankj.utilcode.util.PermissionUtils.OnRationaleListener.ShouldRequest; import java.util.ArrayList; import java.util.Arrays; @@ -25,7 +22,12 @@ import java.util.List; import java.util.Set; -import static com.blankj.utilcode.constant.PermissionConstants.Permission; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.content.ContextCompat; + +import static com.blankj.utilcode.constant.PermissionConstants.PermissionGroup; /** *@@ -40,7 +42,9 @@ public final class PermissionUtils { private static PermissionUtils sInstance; private String[] mPermissionsParam; + private OnExplainListener mOnExplainListener; private OnRationaleListener mOnRationaleListener; + private SingleCallback mSingleCallback; private SimpleCallback mSimpleCallback; private FullCallback mFullCallback; private ThemeCallback mThemeCallback; @@ -87,7 +91,13 @@ public static ListgetPermissions(final String packageName) { * @return {@code true}: yes
{@code false}: no */ public static boolean isGranted(final String... permissions) { - for (String permission : permissions) { + Pair, List