From 55c3fc2eb9344eb3278b2690b32488d8a200adaa Mon Sep 17 00:00:00 2001 From: Blankj <625783482@qq.com> Date: Fri, 8 Mar 2019 17:46:44 +0800 Subject: [PATCH 01/61] see 03/08 log --- CHANGELOG.md | 1 + config.gradle | 17 ++++++------- gradle.properties | 4 ++- .../com/blankj/launcher/pkg/MainActivity.kt | 2 +- .../pkg/src/main/res/layout/activity_main.xml | 18 ++++++------- lib/base/build.gradle | 6 ++--- .../java/com/blankj/lib/base/BaseActivity.kt | 2 +- .../com/blankj/lib/base/BaseApplication.kt | 2 +- .../com/blankj/lib/base/BaseDrawerActivity.kt | 6 ++--- .../java/com/blankj/lib/base/BaseFragment.kt | 6 ++--- .../blankj/lib/base/rv/BaseViewHolder.java | 4 +-- .../lib/base/rv/RecycleViewDivider.java | 10 ++++---- .../lib/base/rv/adapter/BaseAdapter.java | 6 ++--- .../lib/base/rv/adapter/SingleAdapter.java | 2 +- .../src/main/res/layout/activity_back.xml | 14 +++++------ .../src/main/res/layout/activity_drawer.xml | 6 ++--- subutil/lib/build.gradle | 6 ++--- .../blankj/subutil/util/LocationUtils.java | 2 +- .../com/blankj/subutil/util/PinyinUtils.java | 2 +- .../java/com/blankj/subutil/util/Utils.java | 4 +-- .../blankj/subutil/pkg/helper/DialogHelper.kt | 2 +- utilcode/lib/build.gradle | 8 +++--- utilcode/lib/project.properties | 2 +- .../utilcode/constant/MemoryConstants.java | 2 +- .../constant/PermissionConstants.java | 2 +- .../utilcode/constant/TimeConstants.java | 2 +- .../blankj/utilcode/util/ActivityUtils.java | 9 ++++--- .../blankj/utilcode/util/AntiShakeUtils.java | 5 ++-- .../com/blankj/utilcode/util/AppUtils.java | 5 ++-- .../com/blankj/utilcode/util/BarUtils.java | 11 ++++---- .../blankj/utilcode/util/BrightnessUtils.java | 5 ++-- .../utilcode/util/CacheDiskStaticUtils.java | 3 ++- .../blankj/utilcode/util/CacheDiskUtils.java | 3 ++- .../utilcode/util/CacheDoubleStaticUtils.java | 3 ++- .../utilcode/util/CacheDoubleUtils.java | 2 +- .../utilcode/util/CacheMemoryStaticUtils.java | 2 +- .../utilcode/util/CacheMemoryUtils.java | 4 +-- .../com/blankj/utilcode/util/ColorUtils.java | 12 ++++----- .../com/blankj/utilcode/util/CrashUtils.java | 4 +-- .../com/blankj/utilcode/util/DeviceUtils.java | 4 +-- .../blankj/utilcode/util/FragmentUtils.java | 21 ++++++++-------- .../com/blankj/utilcode/util/ImageUtils.java | 14 +++++------ .../com/blankj/utilcode/util/IntentUtils.java | 4 +-- .../com/blankj/utilcode/util/LogUtils.java | 8 +++--- .../blankj/utilcode/util/MetaDataUtils.java | 2 +- .../blankj/utilcode/util/NetworkUtils.java | 2 +- .../utilcode/util/NotificationUtils.java | 6 ++--- .../com/blankj/utilcode/util/ObjectUtils.java | 6 ++--- .../blankj/utilcode/util/PermissionUtils.java | 8 +++--- .../com/blankj/utilcode/util/PhoneUtils.java | 2 +- .../blankj/utilcode/util/ProcessUtils.java | 4 +-- .../com/blankj/utilcode/util/RegexUtils.java | 2 +- .../blankj/utilcode/util/ResourceUtils.java | 2 +- .../blankj/utilcode/util/SPStaticUtils.java | 2 +- .../com/blankj/utilcode/util/SPUtils.java | 2 +- .../com/blankj/utilcode/util/ScreenUtils.java | 5 ++-- .../blankj/utilcode/util/SnackbarUtils.java | 14 +++++------ .../com/blankj/utilcode/util/SpanUtils.java | 16 ++++++------ .../com/blankj/utilcode/util/StringUtils.java | 4 +-- .../com/blankj/utilcode/util/ThreadUtils.java | 7 +++--- .../com/blankj/utilcode/util/TimeUtils.java | 2 +- .../com/blankj/utilcode/util/ToastUtils.java | 10 ++++---- .../com/blankj/utilcode/util/UriUtils.java | 25 +++++++++++++------ .../java/com/blankj/utilcode/util/Utils.java | 2 +- .../blankj/utilcode/util/VibrateUtils.java | 2 +- .../blankj/utilcode/util/ObjectUtilsTest.java | 5 ++-- .../pkg/feature/activity/ActivityActivity.kt | 2 +- .../feature/activity/SubActivityActivity.kt | 2 +- .../feature/bar/BarStatusFragmentActivity.kt | 16 ++++++------ .../pkg/feature/fragment/ContainerFragment.kt | 6 ++--- .../pkg/feature/fragment/FragmentActivity.kt | 6 ++--- .../pkg/feature/image/ImageActivity.kt | 8 +++--- .../pkg/feature/snackbar/SnackbarActivity.kt | 2 +- .../utilcode/pkg/feature/span/SpanActivity.kt | 2 +- .../utilcode/pkg/feature/toast/CustomToast.kt | 2 +- .../pkg/feature/toast/ToastActivity.kt | 2 +- .../utilcode/pkg/helper/DialogHelper.kt | 2 +- .../main/res/layout/activity_adaptscreen.xml | 4 +-- .../res/layout/activity_adaptscreen_close.xml | 4 +-- .../layout/activity_adaptscreen_height.xml | 4 +-- .../res/layout/activity_adaptscreen_width.xml | 4 +-- .../layout/activity_bar_status_fragment.xml | 4 +-- .../src/main/res/layout/activity_fragment.xml | 2 +- .../src/main/res/layout/activity_image.xml | 2 +- 84 files changed, 241 insertions(+), 220 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8271c33548..a1706be701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* `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/config.gradle b/config.gradle index 57c3d35e99..106f066059 100644 --- a/config.gradle +++ b/config.gradle @@ -2,7 +2,7 @@ ext { applicationId = 'com.blankj.androidutilcode' appName = 'Util' - compileSdkVersion = 27 + compileSdkVersion = 28 minSdkVersion = 14 targetSdkVersion = 27 versionCode = 1_023_007 @@ -16,8 +16,8 @@ ext { // lib version kotlin_version = '1.3.0' - support_version = '27.1.1' leakcanary_version = '1.6.3' + androidx_version = '1.0.0' dep = [ plugin : [ @@ -30,19 +30,18 @@ ext { ], // lib - support : [ - appcompat_v7: "com.android.support:appcompat-v7:$support_version", - design : "com.android.support:design:$support_version", - multidex : "com.android.support:multidex:1.0.2", - ], - constraint : "com.android.support.constraint:constraint-layout:1.1.3", + appcompat : "androidx.appcompat:appcompat:$androidx_version", + design : "com.google.android.material:material:$androidx_version", + multidex : "androidx.multidex:multidex:2.0.1", + constraint : "androidx.constraintlayout:constraintlayout:1.1.3", + kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version", leakcanary : [ android : "com.squareup.leakcanary:leakcanary-android:$leakcanary_version", android_no_op : "com.squareup.leakcanary:leakcanary-android-no-op:$leakcanary_version", support_fragment: "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanary_version" ], - free_proguard: "com.blankj:free-proguard:0.0.7", + free_proguard: "com.blankj:free-proguard:0.0.12", adapt_screen : "com.blankj:adapt-screen:0.0.3", gson : "com.google.code.gson:gson:2.8.2", diff --git a/gradle.properties b/gradle.properties index e98b0a89fc..ad5471a961 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,6 @@ # 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 \ No newline at end of file +#org.gradle.jvmargs=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 +android.enableJetifier=true +android.useAndroidX=true \ No newline at end of file diff --git a/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt b/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt index 27d29a032a..e6dc516ed6 100644 --- a/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt +++ b/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt @@ -2,7 +2,7 @@ package com.blankj.launcher.pkg import android.graphics.Color import android.os.Bundle -import android.support.v7.app.ActionBarDrawerToggle +import androidx.appcompat.app.ActionBarDrawerToggle import android.view.View import android.widget.ImageView import com.blankj.lib.base.BaseDrawerActivity diff --git a/launcher/pkg/src/main/res/layout/activity_main.xml b/launcher/pkg/src/main/res/layout/activity_main.xml index 3b31dafe32..ee8b62a6fa 100644 --- a/launcher/pkg/src/main/res/layout/activity_main.xml +++ b/launcher/pkg/src/main/res/layout/activity_main.xml @@ -1,17 +1,17 @@ - - - - - - + + - @@ -69,5 +69,5 @@ android:text="@string/sub_util" /> - - + + diff --git a/lib/base/build.gradle b/lib/base/build.gradle index bd369d23ee..8c6cb29835 100644 --- a/lib/base/build.gradle +++ b/lib/base/build.gradle @@ -7,9 +7,9 @@ dependencies { api project(':utilcode-lib') api project(':subutil-lib') - api dep.support.appcompat_v7 - api dep.support.design - api dep.support.multidex + api dep.appcompat + api dep.design + api dep.multidex api dep.constraint api dep.kotlin api dep.free_proguard diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.kt b/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.kt index deb05718a9..b1b3086f14 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.kt +++ b/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.kt @@ -2,7 +2,7 @@ package com.blankj.lib.base import android.app.Activity import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import android.view.LayoutInflater import android.view.View import com.blankj.utilcode.util.AntiShakeUtils diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.kt b/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.kt index f3eb078f79..873c71fa49 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.kt +++ b/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.kt @@ -2,7 +2,7 @@ package com.blankj.lib.base 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 import com.blankj.utilcode.util.LogUtils diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.kt b/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.kt index a29cc60cc8..3514d2fdd3 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.kt +++ b/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.kt @@ -2,8 +2,8 @@ package com.blankj.lib.base import android.content.Intent import android.net.Uri -import android.support.annotation.StringRes -import android.support.v4.widget.DrawerLayout +import androidx.annotation.StringRes +import androidx.drawerlayout.widget.DrawerLayout import android.view.LayoutInflater import android.widget.FrameLayout import com.blankj.utilcode.util.ActivityUtils @@ -20,7 +20,7 @@ import kotlinx.android.synthetic.main.activity_drawer.* */ abstract class BaseDrawerActivity : BaseActivity() { - protected lateinit var mBaseDrawerRootLayout: DrawerLayout + protected lateinit var mBaseDrawerRootLayout: androidx.drawerlayout.widget.DrawerLayout protected lateinit var mBaseDrawerContainerView: FrameLayout override fun isSwipeBack(): Boolean { diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.kt b/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.kt index 42e7073529..3db893bea2 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.kt +++ b/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.kt @@ -3,8 +3,8 @@ package com.blankj.lib.base import android.app.Activity import android.content.Context import android.os.Bundle -import android.support.annotation.IdRes -import android.support.v4.app.Fragment +import androidx.annotation.IdRes +import androidx.fragment.app.Fragment import android.util.Log import android.view.LayoutInflater import android.view.View @@ -19,7 +19,7 @@ import com.blankj.utilcode.util.AntiShakeUtils * desc : base about v4-fragment * ``` */ -abstract class BaseFragment : Fragment(), IBaseView { +abstract class BaseFragment : androidx.fragment.app.Fragment(), IBaseView { companion object { private const val TAG = "BaseFragment" diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java index ee47e751f5..6441f8c1fd 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java +++ b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java @@ -1,7 +1,7 @@ package com.blankj.lib.base.rv; -import android.support.annotation.IdRes; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.IdRes; +import androidx.recyclerview.widget.RecyclerView; import android.util.SparseArray; import android.view.View; diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java b/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java index 3d2b90f302..dd20894e10 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java +++ b/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java @@ -5,11 +5,11 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.ViewCompat; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.RecyclerView; import android.view.View; import android.widget.LinearLayout; diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/BaseAdapter.java b/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/BaseAdapter.java index f5acee0bb3..b8cf5ae12d 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/BaseAdapter.java +++ b/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/BaseAdapter.java @@ -1,9 +1,9 @@ package com.blankj.lib.base.rv.adapter; import android.content.Context; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/SingleAdapter.java b/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/SingleAdapter.java index 619c8fc688..b7e81b892b 100644 --- a/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/SingleAdapter.java +++ b/lib/base/src/main/java/com/blankj/lib/base/rv/adapter/SingleAdapter.java @@ -1,6 +1,6 @@ package com.blankj.lib.base.rv.adapter; -import android.support.annotation.LayoutRes; +import androidx.annotation.LayoutRes; import java.util.List; diff --git a/lib/base/src/main/res/layout/activity_back.xml b/lib/base/src/main/res/layout/activity_back.xml index 5747922950..848cc885fe 100644 --- a/lib/base/src/main/res/layout/activity_back.xml +++ b/lib/base/src/main/res/layout/activity_back.xml @@ -1,26 +1,26 @@ - - - - + - - - + + diff --git a/lib/base/src/main/res/layout/activity_drawer.xml b/lib/base/src/main/res/layout/activity_drawer.xml index 1fec3fc953..697e83f643 100644 --- a/lib/base/src/main/res/layout/activity_drawer.xml +++ b/lib/base/src/main/res/layout/activity_drawer.xml @@ -1,5 +1,5 @@ - - - + diff --git a/subutil/lib/build.gradle b/subutil/lib/build.gradle index a8b9264e6c..8f8aa8198f 100644 --- a/subutil/lib/build.gradle +++ b/subutil/lib/build.gradle @@ -1,7 +1,7 @@ apply { from "${rootDir.path}/config_lib.gradle" - plugin "tech.harmonysoft.oss.traute" +// plugin "tech.harmonysoft.oss.traute" plugin "com.github.dcendents.android-maven" plugin "com.jfrog.bintray" plugin "readme-sub" @@ -13,8 +13,8 @@ readme { } dependencies { - compileOnly dep.support.appcompat_v7 - compileOnly dep.support.design + compileOnly dep.appcompat + compileOnly dep.design api(dep.glide) { exclude group: "com.android.support" } diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java index 7ee8747902..0c177b534c 100755 --- a/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java +++ b/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java @@ -11,7 +11,7 @@ import android.location.LocationProvider; import android.os.Bundle; import android.provider.Settings; -import android.support.annotation.RequiresPermission; +import androidx.annotation.RequiresPermission; import android.util.Log; import java.io.IOException; diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java index 22486b3a91..934408c65e 100644 --- a/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java +++ b/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java @@ -1,6 +1,6 @@ package com.blankj.subutil.util; -import android.support.v4.util.SimpleArrayMap; +import androidx.collection.SimpleArrayMap; /** *
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java
index 9cbf4e06fd..91b336abcf 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java
@@ -7,8 +7,8 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.lang.reflect.InvocationTargetException;
 
diff --git a/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt b/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt
index 45e67a4a0d..9eba25c622 100644
--- a/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt
+++ b/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt
@@ -1,6 +1,6 @@
 package com.blankj.subutil.pkg.helper
 
-import android.support.v7.app.AlertDialog
+import androidx.appcompat.app.AlertDialog
 import com.blankj.subutil.pkg.R
 import com.blankj.utilcode.util.ActivityUtils
 import com.blankj.utilcode.util.PermissionUtils
diff --git a/utilcode/lib/build.gradle b/utilcode/lib/build.gradle
index 3570124816..41b0dacaa4 100644
--- a/utilcode/lib/build.gradle
+++ b/utilcode/lib/build.gradle
@@ -1,7 +1,7 @@
 apply {
     from "${rootDir.path}/config_lib.gradle"
 
-    plugin "tech.harmonysoft.oss.traute"
+//    plugin "tech.harmonysoft.oss.traute"
     plugin "com.github.dcendents.android-maven"
     plugin "com.jfrog.bintray"
     plugin "readme-core"
@@ -17,10 +17,10 @@ apply from: "${rootDir.path}/gradle/bintrayUploadAndroid.gradle"
 dependencies {
     compile dep.gson
 
-    compileOnly dep.support.appcompat_v7
-    compileOnly dep.support.design
+    compileOnly dep.appcompat
+    compileOnly dep.design
 
     testImplementation dep.junit
     testImplementation dep.robolectric
-    testImplementation dep.support.appcompat_v7
+    testImplementation dep.appcompat
 }
\ No newline at end of file
diff --git a/utilcode/lib/project.properties b/utilcode/lib/project.properties
index 22ae3b8603..d0f2a3f7e0 100644
--- a/utilcode/lib/project.properties
+++ b/utilcode/lib/project.properties
@@ -1,7 +1,7 @@
 #project
 project.name=UtilCode
 project.groupId=com.blankj
-project.artifactId=utilcode
+project.artifactId=utilcodex
 project.packaging=aar
 project.siteUrl=https://github.com/Blankj/AndroidUtilCode
 project.gitUrl=https://github.com/Blankj/AndroidUtilCode.git
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.java b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.java
index b68bfcb113..5c05c0163e 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.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/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java
index 76f7e9a217..6db826e4ab 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java
@@ -4,7 +4,7 @@
 import android.Manifest.permission;
 import android.annotation.SuppressLint;
 import android.os.Build;
-import android.support.annotation.StringDef;
+import androidx.annotation.StringDef;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/TimeConstants.java b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/TimeConstants.java
index 9932037bf8..45090576e3 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/TimeConstants.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java
index 4b8a9a07b5..9dd16d6e48 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java
@@ -10,15 +10,16 @@
 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.v4.app.ActivityOptionsCompat;
-import android.support.v4.util.Pair;
 import android.util.Log;
 import android.view.View;
 
 import java.util.List;
 
+import androidx.annotation.AnimRes;
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.util.Pair;
+
 /**
  * 
  *     author: Blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java
index 7e87e73474..ca9036225e 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java
@@ -1,9 +1,10 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
 import android.view.View;
 
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+
 /**
  * 
  *     author: blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java
index 136f27b5ed..357c423fc6 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java
@@ -17,8 +17,6 @@
 import android.net.Uri;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.v4.content.FileProvider;
 import android.util.Log;
 
 import java.io.File;
@@ -27,6 +25,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.annotation.NonNull;
+import androidx.core.content.FileProvider;
+
 /**
  * 
  *     author: Blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java
index 7b5509b2b5..22178a5c20 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java
@@ -8,11 +8,6 @@
 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.util.Log;
 import android.util.TypedValue;
 import android.view.Display;
@@ -27,6 +22,12 @@
 
 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;
 
 /**
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java
index f9344b0a59..bacc519540 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java
+++ b/utilcode/lib/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
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java
index bb48a4b5cf..c5a9a17a6d 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java
index 99aef6b078..2e6637febf 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java
@@ -8,7 +8,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.annotation.NonNull;
 import android.util.Log;
 
 import com.blankj.utilcode.constant.CacheConstants;
@@ -37,6 +36,8 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
+import androidx.annotation.NonNull;
+
 /**
  * 
  *     author: Blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java
index 2ef267bd01..6dbb9f7475 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java
index c800423c78..aca1c25837 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java
+++ b/utilcode/lib/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;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java
index 56abfba117..aedcfa7fc4 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java
index d0e06e394d..ddaa2baed9 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/ColorUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ColorUtils.java
index 4c0c22232b..a6603cfc44 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ColorUtils.java
+++ b/utilcode/lib/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;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java
index 9ef930c467..a096321cf4 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java
@@ -5,8 +5,8 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
 import android.util.Log;
 
 import java.io.BufferedWriter;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java
index c1c2c3c76e..d0c1788a02 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java
@@ -8,8 +8,8 @@
 import android.os.Build;
 import android.os.PowerManager;
 import android.provider.Settings;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
 import android.text.TextUtils;
 
 import java.io.File;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java
index 43b8537e75..9e8ae14ef1 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java
@@ -3,16 +3,6 @@
 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;
 
@@ -20,6 +10,17 @@
 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
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java
index 83e01eb1ad..cbee7dd4bd 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java
@@ -27,13 +27,13 @@
 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 androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.core.content.ContextCompat;
 import android.view.View;
 
 import java.io.BufferedOutputStream;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java
index 6faa37d043..1e26dc8a9a 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java
@@ -8,8 +8,8 @@
 import android.os.Bundle;
 import android.provider.MediaStore;
 import android.provider.Settings;
-import android.support.annotation.RequiresPermission;
-import android.support.v4.content.FileProvider;
+import androidx.annotation.RequiresPermission;
+import androidx.core.content.FileProvider;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java
index e1e2e78600..f5d814207d 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java
@@ -12,10 +12,10 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.RequiresApi;
-import android.support.v4.util.SimpleArrayMap;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.RequiresApi;
+import androidx.collection.SimpleArrayMap;
 import android.util.Log;
 
 import com.google.gson.Gson;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java
index 6f6cf85b80..bd4b8da935 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java
+++ b/utilcode/lib/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;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java
index f281d777c2..3171837f46 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java
@@ -7,7 +7,7 @@
 import android.net.NetworkInfo;
 import android.net.wifi.WifiManager;
 import android.os.Build;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresPermission;
 import android.telephony.TelephonyManager;
 import android.text.format.Formatter;
 import android.util.Log;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java
index b8163d2e66..73a900b465 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java
@@ -5,9 +5,9 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.support.annotation.Nullable;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
+import androidx.annotation.Nullable;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java
index be5491ece0..3c0c087a39 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java
@@ -1,9 +1,9 @@
 package com.blankj.utilcode.util;
 
 import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.support.v4.util.LongSparseArray;
-import android.support.v4.util.SimpleArrayMap;
+import androidx.annotation.RequiresApi;
+import androidx.collection.LongSparseArray;
+import androidx.collection.SimpleArrayMap;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java
index 235a0f3f94..1cb3df0156 100755
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java
@@ -10,10 +10,10 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.content.ContextCompat;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.WindowManager;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java
index 99068781a4..f407f81b5f 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java
@@ -7,7 +7,7 @@
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresPermission;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java
index 7db75522d9..00c2bf6f73 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java
@@ -10,8 +10,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
 import android.util.Log;
 
 import java.io.BufferedReader;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java
index ba57fab956..817a94149f 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.v4.util.SimpleArrayMap;
+import androidx.collection.SimpleArrayMap;
 
 import com.blankj.utilcode.constant.RegexConstants;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java
index 92424163bb..ee41e95958 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.RawRes;
+import androidx.annotation.RawRes;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java
index d3e21fb873..21274c3023 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java
@@ -1,7 +1,7 @@
 package com.blankj.utilcode.util;
 
 import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import java.util.Map;
 import java.util.Set;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java
index 554a2ed586..a9d18a1a55 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java
@@ -3,7 +3,7 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
index c3e089a90f..f55e4a21db 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
@@ -7,12 +7,11 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Point;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
 import android.util.DisplayMetrics;
 import android.view.Surface;
 import android.view.View;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java
index b164e6154e..eab1990d29 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java
@@ -1,12 +1,12 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import com.google.android.material.snackbar.Snackbar;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.style.ForegroundColorSpan;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java
index 641204fd63..d79cf9262b 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java
@@ -14,14 +14,14 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
 import android.text.Layout;
 import android.text.Layout.Alignment;
 import android.text.SpannableStringBuilder;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java
index c3254e3d32..70f0defe50 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java
@@ -1,8 +1,8 @@
 package com.blankj.utilcode.util;
 
 import android.content.res.Resources;
-import android.support.annotation.ArrayRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.ArrayRes;
+import androidx.annotation.StringRes;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java
index ba7122e366..819af790e8 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java
@@ -2,9 +2,6 @@
 
 import android.os.Handler;
 import android.os.Looper;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -21,6 +18,10 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 /**
  * 
  *     author: Blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java
index adaa920474..a5286b0fbe 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import com.blankj.utilcode.constant.TimeConstants;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java
index b4fe658945..b25360e52c 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java
@@ -14,11 +14,11 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.StringRes;
-import android.support.v4.app.NotificationManagerCompat;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.StringRes;
+import androidx.core.app.NotificationManagerCompat;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java
index 98f3ef66a8..8e4fd9d09c 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java
@@ -8,12 +8,14 @@
 import android.os.Environment;
 import android.provider.DocumentsContract;
 import android.provider.MediaStore;
-import android.support.annotation.NonNull;
-import android.support.v4.content.FileProvider;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.File;
 
+import androidx.annotation.NonNull;
+import androidx.core.content.FileProvider;
+
 /**
  * 
  *     author: Blankj
@@ -70,12 +72,19 @@ public static File uri2File(@NonNull final Uri uri) {
                 Log.d("UriUtils", uri.toString() + " parse failed. -> 1");
                 return null;
             } else if ("com.android.providers.downloads.documents".equals(authority)) {
-                final String id = DocumentsContract.getDocumentId(uri);
-                final Uri contentUri = ContentUris.withAppendedId(
-                        Uri.parse("content://downloads/public_downloads"),
-                        Long.valueOf(id)
-                );
-                return getFileFromUri(contentUri, 2);
+                String id = DocumentsContract.getDocumentId(uri);
+                if (!TextUtils.isEmpty(id)) {
+                    if (id.startsWith("raw:")) {
+                        return new File(id.substring(4));
+                    }
+                    final Uri contentUri = ContentUris.withAppendedId(
+                            Uri.parse(Environment.DIRECTORY_DOWNLOADS),
+                            Long.valueOf(id)
+                    );
+                    return getFileFromUri(contentUri, 2);
+                }
+                Log.d("UriUtils", uri.toString() + " parse failed. -> 3");
+                return null;
             } else if ("com.android.providers.media.documents".equals(authority)) {
                 final String docId = DocumentsContract.getDocumentId(uri);
                 final String[] split = docId.split(":");
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java
index 52b82376e1..d858e4ad22 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java
@@ -7,7 +7,7 @@
 import android.app.Application.ActivityLifecycleCallbacks;
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v4.content.FileProvider;
+import androidx.core.content.FileProvider;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java
index a57bbb8241..622d657817 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java
@@ -2,7 +2,7 @@
 
 import android.content.Context;
 import android.os.Vibrator;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresPermission;
 
 import static android.Manifest.permission.VIBRATE;
 
diff --git a/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java b/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java
index a0203f78fc..ed12c24d8d 100644
--- a/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java
+++ b/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java
@@ -1,7 +1,5 @@
 package com.blankj.utilcode.util;
 
-import android.support.v4.util.LongSparseArray;
-import android.support.v4.util.SimpleArrayMap;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
@@ -12,6 +10,9 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 
+import androidx.collection.LongSparseArray;
+import androidx.collection.SimpleArrayMap;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
index 5ace21f5b1..f3d3600a27 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
@@ -6,7 +6,7 @@ import android.graphics.Bitmap
 import android.graphics.drawable.BitmapDrawable
 import android.os.Build
 import android.os.Bundle
-import android.support.v4.app.ActivityOptionsCompat
+import androidx.core.app.ActivityOptionsCompat
 import android.view.View
 import android.view.Window
 import com.blankj.lib.base.BaseTitleBarActivity
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
index 4815032936..864f1c12b4 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
@@ -2,7 +2,7 @@ package com.blankj.utilcode.pkg.feature.activity
 
 import android.os.Build
 import android.os.Bundle
-import android.support.v4.app.ActivityCompat
+import androidx.core.app.ActivityCompat
 import android.view.View
 import android.view.Window
 import com.blankj.lib.base.BaseTitleBarActivity
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt
index b2633ddf5c..0dac18c72c 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt
@@ -3,10 +3,10 @@ package com.blankj.utilcode.pkg.feature.bar
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
-import android.support.design.widget.BottomNavigationView
-import android.support.v4.app.Fragment
-import android.support.v4.app.FragmentPagerAdapter
-import android.support.v4.view.ViewPager
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentPagerAdapter
+import androidx.viewpager.widget.ViewPager
 import android.view.View
 import com.blankj.lib.base.BaseActivity
 import com.blankj.utilcode.pkg.R
@@ -37,7 +37,7 @@ class BarStatusFragmentActivity : BaseActivity() {
             R.id.barStatusFragmentNavigationCustom
     )
 
-    private val mFragmentList = ArrayList()
+    private val mFragmentList = ArrayList()
 
     private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener l@{ item ->
         when (item.itemId) {
@@ -78,8 +78,8 @@ class BarStatusFragmentActivity : BaseActivity() {
         mFragmentList.add(BarStatusCustomFragment.newInstance())
 
         barStatusFragmentVp.offscreenPageLimit = 3
-        barStatusFragmentVp.adapter = object : FragmentPagerAdapter(supportFragmentManager) {
-            override fun getItem(position: Int): Fragment {
+        barStatusFragmentVp.adapter = object : androidx.fragment.app.FragmentPagerAdapter(supportFragmentManager) {
+            override fun getItem(position: Int): androidx.fragment.app.Fragment {
                 return mFragmentList[position]
             }
 
@@ -88,7 +88,7 @@ class BarStatusFragmentActivity : BaseActivity() {
             }
         }
 
-        barStatusFragmentVp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
+        barStatusFragmentVp.addOnPageChangeListener(object : androidx.viewpager.widget.ViewPager.OnPageChangeListener {
             override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
 
             override fun onPageSelected(position: Int) {
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
index ca0289a158..117c7d121e 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
@@ -2,8 +2,8 @@ package com.blankj.utilcode.pkg.feature.fragment
 
 import android.os.Build
 import android.os.Bundle
-import android.support.annotation.RequiresApi
-import android.support.v4.app.Fragment
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.Fragment
 import android.transition.*
 import android.view.View
 import com.blankj.lib.base.BaseLazyFragment
@@ -129,7 +129,7 @@ class ContainerFragment : BaseLazyFragment(), FragmentUtils.OnBackClickListener
         }
     }
 
-    private fun addSharedElement(fragment: Fragment): Fragment {
+    private fun addSharedElement(fragment: androidx.fragment.app.Fragment): androidx.fragment.app.Fragment {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             fragment.sharedElementEnterTransition = DetailTransition()
             fragment.enterTransition = Fade()
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
index b768f563e5..6e3137b9c6 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
@@ -4,8 +4,8 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.os.PersistableBundle
-import android.support.design.widget.BottomNavigationView
-import android.support.v4.app.Fragment
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import androidx.fragment.app.Fragment
 import android.view.View
 import com.blankj.lib.base.BaseActivity
 import com.blankj.utilcode.pkg.R
@@ -30,7 +30,7 @@ class FragmentActivity : BaseActivity() {
         }
     }
 
-    private val mFragments = arrayListOf()
+    private val mFragments = arrayListOf()
     private var curIndex: Int = 0
 
     private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
index 496c5a4032..636d92c030 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
@@ -6,9 +6,9 @@ import android.graphics.Bitmap
 import android.graphics.Color
 import android.os.Build
 import android.os.Bundle
-import android.support.annotation.LayoutRes
-import android.support.annotation.StringRes
-import android.support.v7.widget.LinearLayoutManager
+import androidx.annotation.LayoutRes
+import androidx.annotation.StringRes
+import androidx.recyclerview.widget.LinearLayoutManager
 import android.view.View
 import android.widget.ImageView
 import android.widget.TextView
@@ -92,7 +92,7 @@ class ImageActivity : BaseActivity() {
         }
 
         imageRv.adapter = ImageAdapter(mList, R.layout.item_image)
-        imageRv.layoutManager = LinearLayoutManager(this)
+        imageRv.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
     }
 
     override fun doBusiness() {}
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
index 4bd07d274e..34d3914fe1 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
@@ -4,7 +4,7 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.Color
 import android.os.Bundle
-import android.support.annotation.StringRes
+import androidx.annotation.StringRes
 import android.text.SpannableStringBuilder
 import android.view.View
 import android.view.ViewGroup
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
index f3a1a3ee02..7c5fd45308 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
@@ -5,7 +5,7 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.*
 import android.os.Bundle
-import android.support.annotation.ColorInt
+import androidx.annotation.ColorInt
 import android.text.Layout
 import android.text.SpannableStringBuilder
 import android.text.TextPaint
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
index 314ba33d59..458ecbb3fb 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
@@ -2,7 +2,7 @@ package com.blankj.utilcode.pkg.feature.toast
 
 import android.os.Handler
 import android.os.Looper
-import android.support.annotation.StringRes
+import androidx.annotation.StringRes
 import android.widget.TextView
 import android.widget.Toast
 
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
index ea6c10c24d..40055d14b9 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
@@ -4,7 +4,7 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.Color
 import android.os.Bundle
-import android.support.v4.content.ContextCompat
+import androidx.core.content.ContextCompat
 import android.view.Gravity
 import android.view.View
 import com.blankj.lib.base.BaseTitleBarActivity
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
index 7e6094414a..c3247b1312 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.pkg.helper
 
-import android.support.v7.app.AlertDialog
+import androidx.appcompat.app.AlertDialog
 import android.text.method.ScrollingMovementMethod
 import android.view.LayoutInflater
 import android.view.View
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
index 003c6f5840..e33848b84d 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
@@ -1,5 +1,5 @@
 
-
 
-
+
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml
index c3f88ecba3..e43cbb2bb5 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml
@@ -8,7 +8,7 @@
     android:background="@color/white"
     tools:context=".feature.adaptScreen.CloseAdaptActivity">
 
-    
 
@@ -42,6 +42,6 @@
             android:textSize="30pt"
             app:layout_constraintTop_toBottomOf="@id/adaptScreenCloseAdaptDpTv" />
 
-    
+    
 
 
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml
index 0b207d97f5..07c76be55b 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml
@@ -8,7 +8,7 @@
     android:background="@color/white"
     tools:context=".feature.adaptScreen.HeightActivity">
 
-    
 
@@ -94,6 +94,6 @@
         
 
 
-    
+    
 
 
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml
index 46e0f2f1a2..5a791d924f 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml
@@ -8,7 +8,7 @@
     android:background="@color/white"
     tools:context=".feature.adaptScreen.WidthActivity">
 
-    
 
@@ -147,6 +147,6 @@
 
         
 
-    
+    
 
 
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml b/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml
index c5f975b58f..1a36770b58 100644
--- a/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml
@@ -7,7 +7,7 @@
     android:background="@color/white"
     android:orientation="vertical">
 
-    
 
-    
 
-    
 
-    

From 70b6089109b6e58734d0a500820f54cb41858eba Mon Sep 17 00:00:00 2001
From: Blankj <625783482@qq.com>
Date: Fri, 8 Mar 2019 18:07:14 +0800
Subject: [PATCH 02/61] see 03/08 log

---
 utilcode/README-CN.md | 3 +++
 utilcode/README.md    | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/utilcode/README-CN.md b/utilcode/README-CN.md
index f3756be966..7fc06ebf99 100644
--- a/utilcode/README-CN.md
+++ b/utilcode/README-CN.md
@@ -3,6 +3,9 @@
 Gradle:
 ```groovy
 implementation 'com.blankj:utilcode:1.23.7'
+
+// if u use AndroidX, use the following
+implementation 'com.blankj:utilcodex:1.23.7'
 ```
 
 
diff --git a/utilcode/README.md b/utilcode/README.md
index 75d8757892..094cc44c08 100644
--- a/utilcode/README.md
+++ b/utilcode/README.md
@@ -3,6 +3,9 @@
 Gradle:
 ```groovy
 implementation 'com.blankj:utilcode:1.23.7'
+
+// if u use AndroidX, use the following
+implementation 'com.blankj:utilcodex:1.23.7'
 ```
 
 

From 2fa66306221456a5be12d9d201c7495958596fb4 Mon Sep 17 00:00:00 2001
From: Blankj <625783482@qq.com>
Date: Mon, 11 Mar 2019 20:45:31 +0800
Subject: [PATCH 03/61] see 03/11 log

---
 utilcode/lib/project.properties | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utilcode/lib/project.properties b/utilcode/lib/project.properties
index d0f2a3f7e0..d238eda740 100644
--- a/utilcode/lib/project.properties
+++ b/utilcode/lib/project.properties
@@ -1,9 +1,9 @@
 #project
-project.name=UtilCode
+project.name=UtilCodeX
 project.groupId=com.blankj
 project.artifactId=utilcodex
 project.packaging=aar
 project.siteUrl=https://github.com/Blankj/AndroidUtilCode
 project.gitUrl=https://github.com/Blankj/AndroidUtilCode.git
 #javadoc
-javadoc.name=UtilCode
\ No newline at end of file
+javadoc.name=UtilCodeX
\ No newline at end of file

From 6b0ff9575675cf0ae15c9c9a85eb249b5591c3a8 Mon Sep 17 00:00:00 2001
From: Blankj <625783482@qq.com>
Date: Mon, 3 Jun 2019 20:49:21 +0800
Subject: [PATCH 04/61] see 06/03 log

---
 .gitignore                                    |  2 +-
 CHANGELOG.md                                  |  1 +
 gradle.properties                             |  8 +++++-
 gradle/config/config.gradle                   | 10 ++++----
 gradle/config/configApp.gradle                |  5 +++-
 launcher/app/build.gradle                     |  6 ++---
 launcher/pkg/build.gradle                     |  2 +-
 .../com/blankj/launcher/pkg/MainActivity.kt   |  2 +-
 .../pkg/src/main/res/layout/activity_main.xml | 18 ++++++-------
 lib/base/build.gradle                         |  2 +-
 .../com/blankj/lib/base/BaseActivity.java     |  5 ++--
 .../com/blankj/lib/base/BaseApplication.java  |  3 ++-
 .../blankj/lib/base/BaseDrawerActivity.java   | 11 ++++----
 .../com/blankj/lib/base/BaseFragment.java     | 13 +++++-----
 .../blankj/lib/base/BaseTitleActivity.java    |  9 ++++---
 .../java/com/blankj/lib/base/IBaseView.java   |  5 ++--
 .../com/blankj/lib/base/rv/BaseAdapter.java   |  5 ++--
 .../java/com/blankj/lib/base/rv/BaseCell.java |  3 ++-
 .../blankj/lib/base/rv/BaseViewHolder.java    |  4 +--
 .../lib/base/rv/RecycleViewDivider.java       | 10 ++++----
 .../main/res/layout/activity_base_title.xml   | 11 ++++----
 .../activity_base_title_stub_scroll.xml       |  4 +--
 .../src/main/res/layout/activity_drawer.xml   |  6 ++---
 subutil/app/build.gradle                      |  2 +-
 subutil/lib/build.gradle                      |  2 +-
 .../blankj/subutil/util/LocationUtils.java    |  2 +-
 .../com/blankj/subutil/util/PinyinUtils.java  |  2 +-
 .../java/com/blankj/subutil/util/Utils.java   |  4 +--
 .../subutil/util/http/ExecutorFactory.java    |  3 ++-
 .../blankj/subutil/util/http/HttpUtils.java   |  3 ++-
 .../com/blankj/subutil/util/http/Request.java |  3 ++-
 .../blankj/subutil/util/http/SSLConfig.java   |  3 ++-
 subutil/pkg/build.gradle                      |  2 +-
 .../blankj/subutil/pkg/helper/DialogHelper.kt |  2 +-
 utilcode/README-CN.md                         |  2 +-
 utilcode/README.md                            |  2 +-
 utilcode/app/build.gradle                     |  2 +-
 utilcode/lib/build.gradle                     |  2 +-
 utilcode/lib/project.properties               |  6 ++---
 .../utilcode/constant/MemoryConstants.java    |  2 +-
 .../constant/PermissionConstants.java         |  2 +-
 .../utilcode/constant/TimeConstants.java      |  2 +-
 .../blankj/utilcode/util/ActivityUtils.java   | 11 ++++----
 .../blankj/utilcode/util/AntiShakeUtils.java  |  5 ++--
 .../com/blankj/utilcode/util/AppUtils.java    |  5 ++--
 .../com/blankj/utilcode/util/BarUtils.java    | 11 ++++----
 .../blankj/utilcode/util/BrightnessUtils.java |  5 ++--
 .../com/blankj/utilcode/util/BusUtils.java    |  5 ++--
 .../utilcode/util/CacheDiskStaticUtils.java   |  3 ++-
 .../blankj/utilcode/util/CacheDiskUtils.java  |  3 ++-
 .../utilcode/util/CacheDoubleStaticUtils.java |  3 ++-
 .../utilcode/util/CacheDoubleUtils.java       |  2 +-
 .../utilcode/util/CacheMemoryStaticUtils.java |  2 +-
 .../utilcode/util/CacheMemoryUtils.java       |  4 +--
 .../com/blankj/utilcode/util/ColorUtils.java  | 12 ++++-----
 .../com/blankj/utilcode/util/CrashUtils.java  |  4 +--
 .../com/blankj/utilcode/util/DeviceUtils.java |  5 ++--
 .../blankj/utilcode/util/FragmentUtils.java   | 21 ++++++++--------
 .../com/blankj/utilcode/util/ImageUtils.java  | 14 +++++------
 .../com/blankj/utilcode/util/IntentUtils.java |  4 +--
 .../blankj/utilcode/util/KeyboardUtils.java   |  3 ++-
 .../com/blankj/utilcode/util/LogUtils.java    |  8 +++---
 .../blankj/utilcode/util/MetaDataUtils.java   |  2 +-
 .../blankj/utilcode/util/NetworkUtils.java    |  5 ++--
 .../utilcode/util/NotificationUtils.java      |  6 ++---
 .../com/blankj/utilcode/util/ObjectUtils.java |  6 ++---
 .../blankj/utilcode/util/PermissionUtils.java |  8 +++---
 .../com/blankj/utilcode/util/PhoneUtils.java  |  2 +-
 .../blankj/utilcode/util/ProcessUtils.java    |  4 +--
 .../com/blankj/utilcode/util/RegexUtils.java  |  2 +-
 .../blankj/utilcode/util/ResourceUtils.java   |  2 +-
 .../blankj/utilcode/util/SPStaticUtils.java   |  2 +-
 .../com/blankj/utilcode/util/SPUtils.java     |  2 +-
 .../com/blankj/utilcode/util/ScreenUtils.java |  4 +--
 .../com/blankj/utilcode/util/ShellUtils.java  |  2 +-
 .../blankj/utilcode/util/SnackbarUtils.java   | 14 +++++------
 .../com/blankj/utilcode/util/SpanUtils.java   | 16 ++++++------
 .../com/blankj/utilcode/util/StringUtils.java |  4 +--
 .../com/blankj/utilcode/util/ThreadUtils.java |  5 ++--
 .../com/blankj/utilcode/util/TimeUtils.java   |  2 +-
 .../com/blankj/utilcode/util/ToastUtils.java  | 10 ++++----
 .../com/blankj/utilcode/util/UriUtils.java    | 25 +++++++++++++------
 .../java/com/blankj/utilcode/util/Utils.java  |  3 ++-
 .../blankj/utilcode/util/VibrateUtils.java    |  2 +-
 .../com/blankj/utilcode/util/BaseTest.java    | 11 +++-----
 .../blankj/utilcode/util/ObjectUtilsTest.java |  5 ++--
 utilcode/pkg/build.gradle                     |  2 +-
 .../pkg/feature/activity/ActivityActivity.kt  |  2 +-
 .../feature/activity/SubActivityActivity.kt   |  2 +-
 .../feature/bar/BarStatusFragmentActivity.kt  | 16 ++++++------
 .../pkg/feature/fragment/ContainerFragment.kt |  6 ++---
 .../pkg/feature/fragment/FragmentActivity.kt  |  6 ++---
 .../pkg/feature/image/ImageActivity.kt        |  4 +--
 .../pkg/feature/snackbar/SnackbarActivity.kt  |  2 +-
 .../utilcode/pkg/feature/span/SpanActivity.kt |  2 +-
 .../utilcode/pkg/feature/toast/CustomToast.kt |  2 +-
 .../pkg/feature/toast/ToastActivity.kt        |  2 +-
 .../utilcode/pkg/helper/DialogHelper.kt       |  5 ++--
 .../main/res/layout/activity_adaptscreen.xml  |  4 +--
 .../res/layout/activity_adaptscreen_close.xml |  4 +--
 .../layout/activity_adaptscreen_height.xml    |  7 +++---
 .../res/layout/activity_adaptscreen_width.xml |  4 +--
 .../layout/activity_bar_status_fragment.xml   |  4 +--
 .../src/main/res/layout/activity_fragment.xml |  2 +-
 .../src/main/res/layout/activity_image.xml    |  3 +--
 105 files changed, 293 insertions(+), 253 deletions(-)

diff --git a/.gitignore b/.gitignore
index 201b88771a..193619553c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,4 @@
 .externalNativeBuild
 /apk
 *.phrof
-/maven
+/busMaven
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 95dfb60cc3..9c48786e89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,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/gradle.properties b/gradle.properties
index 110f0cb7ef..c209c08b84 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -19,4 +19,10 @@
 
 #org.gradle.jvmargs=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
 
-org.gradle.jvmargs=-XX:MaxHeapSize=1024m -Xmx1024m
\ No newline at end of file
+org.gradle.jvmargs=-Xmx8192m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.daemon=true
+org.gradle.configureondemand=true
+org.gradle.parallel=true
+
+android.enableJetifier=true
+android.useAndroidX=true
\ No newline at end of file
diff --git a/gradle/config/config.gradle b/gradle/config/config.gradle
index e455c4dba6..e8c793b6b3 100644
--- a/gradle/config/config.gradle
+++ b/gradle/config/config.gradle
@@ -5,7 +5,7 @@ gradle.ext {
     applicationId = 'com.blankj.androidutilcode'
     appName = 'Util'
 
-    compileSdkVersion = 27
+    compileSdkVersion = 28
     minSdkVersion = 14
     targetSdkVersion = 27
     versionCode = 1_024_000
@@ -13,8 +13,8 @@ gradle.ext {
 
     // lib version
     kotlin_version = '1.3.10'
-    support_version = '27.1.1'
     leakcanary_version = '1.6.3'
+    androidx_version = '1.0.0'
 
     dep = [:]
 
@@ -36,11 +36,11 @@ gradle.ext {
             subutil_lib                : new DepConfig(":subutil:lib"),
             subutil_pkg                : new DepConfig(":subutil:pkg"),
             utilcode_app               : new DepConfig(":utilcode:app"),
-            utilcode_lib               : new DepConfig(false, ":utilcode:lib", "com.blankj:utilcode:$versionName"),
+            utilcode_lib               : new DepConfig(true, ":utilcode:lib", "com.blankj:utilcode:$versionName"),
             utilcode_pkg               : new DepConfig(":utilcode:pkg"),
 
-            support_appcompat_v7       : new DepConfig("com.android.support:appcompat-v7:$support_version"),
-            support_design             : new DepConfig("com.android.support:design:$support_version"),
+            support_appcompat_v7       : new DepConfig("androidx.appcompat:appcompat:$androidx_version"),
+            support_material           : new DepConfig("com.google.android.material:material:$androidx_version"),
             support_multidex           : new DepConfig("com.android.support:multidex:1.0.2"),
 
             constraint                 : new DepConfig("com.android.support.constraint:constraint-layout:1.1.3"),
diff --git a/gradle/config/configApp.gradle b/gradle/config/configApp.gradle
index cb8d5a290a..809cb07cd4 100644
--- a/gradle/config/configApp.gradle
+++ b/gradle/config/configApp.gradle
@@ -42,8 +42,11 @@ android {
     }
 
     dexOptions {
+        preDexLibraries true
         javaMaxHeapSize "8g"
         maxProcessCount 8
+        incremental true
+        dexInProcess = true
     }
 }
 
@@ -57,7 +60,7 @@ dependencies {
 
 private String getSuffix() {
     if (project.path == ":launcher:app") return ""
-    return project.path.replace(":" , "_").substring(0, project.path.length() - 4)
+    return project.path.replace(":", "_").substring(0, project.path.length() - 4)
 }
 
 def configSigning(Project pro) {
diff --git a/launcher/app/build.gradle b/launcher/app/build.gradle
index eb9f8d906f..bf68fb45ff 100644
--- a/launcher/app/build.gradle
+++ b/launcher/app/build.gradle
@@ -4,7 +4,7 @@ apply {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation project(':launcher:pkg')
-    implementation project(':subutil:pkg')
-    implementation project(':utilcode:pkg')
+    implementation gradle.ext.dep.launcher_pkg
+    implementation gradle.ext.dep.subutil_pkg
+    implementation gradle.ext.dep.utilcode_pkg
 }
\ No newline at end of file
diff --git a/launcher/pkg/build.gradle b/launcher/pkg/build.gradle
index 9fe360a5dd..881637b34a 100644
--- a/launcher/pkg/build.gradle
+++ b/launcher/pkg/build.gradle
@@ -4,5 +4,5 @@ apply {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    api project(':lib:base')
+    api gradle.ext.dep.lib_base
 }
\ No newline at end of file
diff --git a/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt b/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt
index 02491cd88d..0e9f0a8477 100644
--- a/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt
+++ b/launcher/pkg/src/main/java/com/blankj/launcher/pkg/MainActivity.kt
@@ -2,7 +2,7 @@ package com.blankj.launcher.pkg
 
 import android.graphics.Color
 import android.os.Bundle
-import android.support.v7.app.ActionBarDrawerToggle
+import androidx.appcompat.app.ActionBarDrawerToggle
 import android.view.View
 import android.widget.ImageView
 import com.blankj.lib.base.BaseDrawerActivity
diff --git a/launcher/pkg/src/main/res/layout/activity_main.xml b/launcher/pkg/src/main/res/layout/activity_main.xml
index 3b31dafe32..ee8b62a6fa 100644
--- a/launcher/pkg/src/main/res/layout/activity_main.xml
+++ b/launcher/pkg/src/main/res/layout/activity_main.xml
@@ -1,17 +1,17 @@
 
-
 
-    
 
-        
 
-            
 
-        
-    
+        
+    
 
     
 
-    
@@ -69,5 +69,5 @@
                 android:text="@string/sub_util" />
 
         
-    
-
+    
+
diff --git a/lib/base/build.gradle b/lib/base/build.gradle
index 370036c062..67f9762d82 100644
--- a/lib/base/build.gradle
+++ b/lib/base/build.gradle
@@ -8,7 +8,7 @@ dependencies {
     api gradle.ext.dep.subutil_lib
 
     api gradle.ext.dep.support_appcompat_v7
-    api gradle.ext.dep.support_design
+    api gradle.ext.dep.support_material
     api gradle.ext.dep.support_multidex
     api gradle.ext.dep.constraint
     api gradle.ext.dep.kotlin
diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.java b/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.java
index caae1d45cf..0c9d8fa419 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/BaseActivity.java
@@ -3,11 +3,12 @@
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.os.Bundle;
-import android.support.annotation.LayoutRes;
-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.swipepanel.SwipePanel;
 import com.blankj.utilcode.util.AntiShakeUtils;
 import com.blankj.utilcode.util.AppUtils;
diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.java b/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.java
index 1e0ddc0b27..5d2eba8260 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/BaseApplication.java
+++ b/lib/base/src/main/java/com/blankj/lib/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;
diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.java b/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.java
index c7f7f1daea..ec3c895f6e 100755
--- a/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/BaseDrawerActivity.java
@@ -3,17 +3,18 @@
 import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.net.Uri;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
-import android.support.design.widget.NavigationView;
-import android.support.v4.widget.DrawerLayout;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.widget.FrameLayout;
 
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.drawerlayout.widget.DrawerLayout;
+
 import com.blankj.utilcode.util.ActivityUtils;
 import com.blankj.utilcode.util.StringUtils;
+import com.google.android.material.navigation.NavigationView;
 
 
 /**
diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.java b/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.java
index 5667f3f02c..0e4e7ba5cc 100755
--- a/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/BaseFragment.java
@@ -4,17 +4,18 @@
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
-import android.support.annotation.IdRes;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.IdRes;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentTransaction;
+
 import com.blankj.utilcode.util.AntiShakeUtils;
 
 /**
diff --git a/lib/base/src/main/java/com/blankj/lib/base/BaseTitleActivity.java b/lib/base/src/main/java/com/blankj/lib/base/BaseTitleActivity.java
index a40230420d..e0ed3ed10a 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/BaseTitleActivity.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/BaseTitleActivity.java
@@ -1,16 +1,17 @@
 package com.blankj.lib.base;
 
 import android.annotation.SuppressLint;
-import android.support.annotation.LayoutRes;
-import android.support.design.widget.CoordinatorLayout;
-import android.support.v7.app.ActionBar;
-import android.support.v7.widget.Toolbar;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewStub;
 import android.widget.FrameLayout;
 
+import androidx.annotation.LayoutRes;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.widget.Toolbar;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
 import com.blankj.utilcode.util.BarUtils;
 import com.blankj.utilcode.util.ColorUtils;
 
diff --git a/lib/base/src/main/java/com/blankj/lib/base/IBaseView.java b/lib/base/src/main/java/com/blankj/lib/base/IBaseView.java
index 29e8553899..b0550f126c 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/IBaseView.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/IBaseView.java
@@ -1,10 +1,11 @@
 package com.blankj.lib.base;
 
 import android.os.Bundle;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.Nullable;
 import android.view.View;
 
+import androidx.annotation.LayoutRes;
+import androidx.annotation.Nullable;
+
 
 /**
  * 
diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseAdapter.java b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseAdapter.java
index 11aa94e015..e69be6c6df 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseAdapter.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseAdapter.java
@@ -1,12 +1,13 @@
 package com.blankj.lib.base.rv;
 
 import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
 import java.util.List;
 
 /**
diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseCell.java b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseCell.java
index cdf42c7882..332c4caee0 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseCell.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseCell.java
@@ -1,10 +1,11 @@
 package com.blankj.lib.base.rv;
 
-import android.support.annotation.NonNull;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.View;
 
+import androidx.annotation.NonNull;
+
 /**
  * 
  *     author: blankj
diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java
index ceb1c46eac..0bd892f317 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/rv/BaseViewHolder.java
@@ -1,7 +1,7 @@
 package com.blankj.lib.base.rv;
 
-import android.support.annotation.IdRes;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.IdRes;
+import androidx.recyclerview.widget.RecyclerView;
 import android.util.SparseArray;
 import android.view.View;
 
diff --git a/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java b/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java
index 3d2b90f302..dd20894e10 100644
--- a/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java
+++ b/lib/base/src/main/java/com/blankj/lib/base/rv/RecycleViewDivider.java
@@ -5,11 +5,11 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.ViewCompat;
+import androidx.recyclerview.widget.RecyclerView;
 import android.view.View;
 import android.widget.LinearLayout;
 
diff --git a/lib/base/src/main/res/layout/activity_base_title.xml b/lib/base/src/main/res/layout/activity_base_title.xml
index b11ecf7341..986d3669b6 100644
--- a/lib/base/src/main/res/layout/activity_base_title.xml
+++ b/lib/base/src/main/res/layout/activity_base_title.xml
@@ -1,24 +1,23 @@
 
-
 
-    
 
-        
-    
+    
 
     
 
-
+
diff --git a/lib/base/src/main/res/layout/activity_base_title_stub_scroll.xml b/lib/base/src/main/res/layout/activity_base_title_stub_scroll.xml
index 96f5e09d49..bd031cfb67 100644
--- a/lib/base/src/main/res/layout/activity_base_title_stub_scroll.xml
+++ b/lib/base/src/main/res/layout/activity_base_title_stub_scroll.xml
@@ -1,5 +1,5 @@
 
-
 
-
+
 
diff --git a/lib/base/src/main/res/layout/activity_drawer.xml b/lib/base/src/main/res/layout/activity_drawer.xml
index 72f70ed969..be44cd718c 100644
--- a/lib/base/src/main/res/layout/activity_drawer.xml
+++ b/lib/base/src/main/res/layout/activity_drawer.xml
@@ -1,5 +1,5 @@
 
-
 
-    
 
-
+
diff --git a/subutil/app/build.gradle b/subutil/app/build.gradle
index a2e0172413..a7027c15ef 100644
--- a/subutil/app/build.gradle
+++ b/subutil/app/build.gradle
@@ -4,5 +4,5 @@ apply {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation project(':subutil:pkg')
+    implementation gradle.ext.dep.subutil_pkg
 }
\ No newline at end of file
diff --git a/subutil/lib/build.gradle b/subutil/lib/build.gradle
index 9dcbe0b542..f3140b4f0b 100644
--- a/subutil/lib/build.gradle
+++ b/subutil/lib/build.gradle
@@ -14,7 +14,7 @@ readme {
 
 dependencies {
     compileOnly gradle.ext.dep.support_appcompat_v7
-    compileOnly gradle.ext.dep.support_design
+    compileOnly gradle.ext.dep.support_material
     api(gradle.ext.dep.glide) {
         exclude group: "com.android.support"
     }
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java
index 7ee8747902..0c177b534c 100755
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java
@@ -11,7 +11,7 @@
 import android.location.LocationProvider;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresPermission;
 import android.util.Log;
 
 import java.io.IOException;
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java
index 22486b3a91..934408c65e 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.subutil.util;
 
-import android.support.v4.util.SimpleArrayMap;
+import androidx.collection.SimpleArrayMap;
 
 /**
  * 
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java
index 9cbf4e06fd..91b336abcf 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/Utils.java
@@ -7,8 +7,8 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.lang.reflect.InvocationTargetException;
 
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/http/ExecutorFactory.java b/subutil/lib/src/main/java/com/blankj/subutil/util/http/ExecutorFactory.java
index f5583397d9..2f26fb9c24 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/http/ExecutorFactory.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/http/ExecutorFactory.java
@@ -2,7 +2,8 @@
 
 import android.os.Handler;
 import android.os.Looper;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/http/HttpUtils.java b/subutil/lib/src/main/java/com/blankj/subutil/util/http/HttpUtils.java
index b952f318cb..bdd4174486 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/http/HttpUtils.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/http/HttpUtils.java
@@ -1,7 +1,8 @@
 package com.blankj.subutil.util.http;
 
 import android.accounts.NetworkErrorException;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/http/Request.java b/subutil/lib/src/main/java/com/blankj/subutil/util/http/Request.java
index fe39b1299c..c6eddf9b96 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/http/Request.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/http/Request.java
@@ -1,6 +1,7 @@
 package com.blankj.subutil.util.http;
 
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
diff --git a/subutil/lib/src/main/java/com/blankj/subutil/util/http/SSLConfig.java b/subutil/lib/src/main/java/com/blankj/subutil/util/http/SSLConfig.java
index b8624af490..0cf43662f2 100644
--- a/subutil/lib/src/main/java/com/blankj/subutil/util/http/SSLConfig.java
+++ b/subutil/lib/src/main/java/com/blankj/subutil/util/http/SSLConfig.java
@@ -2,7 +2,8 @@
 
 import android.annotation.SuppressLint;
 import android.os.Build;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.io.IOException;
 import java.net.InetAddress;
diff --git a/subutil/pkg/build.gradle b/subutil/pkg/build.gradle
index 9fe360a5dd..881637b34a 100644
--- a/subutil/pkg/build.gradle
+++ b/subutil/pkg/build.gradle
@@ -4,5 +4,5 @@ apply {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    api project(':lib:base')
+    api gradle.ext.dep.lib_base
 }
\ No newline at end of file
diff --git a/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt b/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt
index 45e67a4a0d..9eba25c622 100644
--- a/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt
+++ b/subutil/pkg/src/main/java/com/blankj/subutil/pkg/helper/DialogHelper.kt
@@ -1,6 +1,6 @@
 package com.blankj.subutil.pkg.helper
 
-import android.support.v7.app.AlertDialog
+import androidx.appcompat.app.AlertDialog
 import com.blankj.subutil.pkg.R
 import com.blankj.utilcode.util.ActivityUtils
 import com.blankj.utilcode.util.PermissionUtils
diff --git a/utilcode/README-CN.md b/utilcode/README-CN.md
index 445f206121..0bdb622940 100644
--- a/utilcode/README-CN.md
+++ b/utilcode/README-CN.md
@@ -5,7 +5,7 @@ Gradle:
 implementation 'com.blankj:utilcode:1.24.0'
 
 // if u use AndroidX, use the following
-implementation 'com.blankj:utilcodex:1.23.7'
+implementation 'com.blankj:utilcodex:1.24.0'
 ```
 
 
diff --git a/utilcode/README.md b/utilcode/README.md
index f449736061..5a6a295b4c 100644
--- a/utilcode/README.md
+++ b/utilcode/README.md
@@ -5,7 +5,7 @@ Gradle:
 implementation 'com.blankj:utilcode:1.24.0'
 
 // if u use AndroidX, use the following
-implementation 'com.blankj:utilcodex:1.23.7'
+implementation 'com.blankj:utilcodex:1.24.0'
 ```
 
 
diff --git a/utilcode/app/build.gradle b/utilcode/app/build.gradle
index 5616386892..ea5c172cd7 100644
--- a/utilcode/app/build.gradle
+++ b/utilcode/app/build.gradle
@@ -4,5 +4,5 @@ apply {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation project(':utilcode:pkg')
+    implementation gradle.ext.dep.utilcode_pkg
 }
\ No newline at end of file
diff --git a/utilcode/lib/build.gradle b/utilcode/lib/build.gradle
index e4dd3a6716..6d6c599298 100644
--- a/utilcode/lib/build.gradle
+++ b/utilcode/lib/build.gradle
@@ -18,7 +18,7 @@ dependencies {
     compile gradle.ext.dep.gson
 
     compileOnly gradle.ext.dep.support_appcompat_v7
-    compileOnly gradle.ext.dep.support_design
+    compileOnly gradle.ext.dep.support_material
 
     testImplementation gradle.ext.dep.junit
     testImplementation gradle.ext.dep.robolectric
diff --git a/utilcode/lib/project.properties b/utilcode/lib/project.properties
index 22ae3b8603..d238eda740 100644
--- a/utilcode/lib/project.properties
+++ b/utilcode/lib/project.properties
@@ -1,9 +1,9 @@
 #project
-project.name=UtilCode
+project.name=UtilCodeX
 project.groupId=com.blankj
-project.artifactId=utilcode
+project.artifactId=utilcodex
 project.packaging=aar
 project.siteUrl=https://github.com/Blankj/AndroidUtilCode
 project.gitUrl=https://github.com/Blankj/AndroidUtilCode.git
 #javadoc
-javadoc.name=UtilCode
\ No newline at end of file
+javadoc.name=UtilCodeX
\ No newline at end of file
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.java b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.java
index b68bfcb113..5c05c0163e 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/MemoryConstants.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/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java
index 76f7e9a217..6db826e4ab 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java
@@ -4,7 +4,7 @@
 import android.Manifest.permission;
 import android.annotation.SuppressLint;
 import android.os.Build;
-import android.support.annotation.StringDef;
+import androidx.annotation.StringDef;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/TimeConstants.java b/utilcode/lib/src/main/java/com/blankj/utilcode/constant/TimeConstants.java
index 9932037bf8..45090576e3 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/constant/TimeConstants.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java
index d6a671e4fe..de1bfeb005 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ActivityUtils.java
@@ -10,14 +10,15 @@
 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.util.Pair;
 import android.util.Log;
 import android.view.View;
 
+import androidx.annotation.AnimRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.util.Pair;
+
 import java.util.List;
 
 /**
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java
index 7e87e73474..ca9036225e 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AntiShakeUtils.java
@@ -1,9 +1,10 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
 import android.view.View;
 
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+
 /**
  * 
  *     author: blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java
index a9368be59f..5a9194ce66 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/AppUtils.java
@@ -17,8 +17,6 @@
 import android.net.Uri;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.v4.content.FileProvider;
 import android.util.Log;
 
 import java.io.File;
@@ -27,6 +25,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.annotation.NonNull;
+import androidx.core.content.FileProvider;
+
 /**
  * 
  *     author: Blankj
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java
index 7b5509b2b5..22178a5c20 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BarUtils.java
@@ -8,11 +8,6 @@
 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.util.Log;
 import android.util.TypedValue;
 import android.view.Display;
@@ -27,6 +22,12 @@
 
 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;
 
 /**
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java
index f9344b0a59..bacc519540 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BrightnessUtils.java
+++ b/utilcode/lib/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
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BusUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BusUtils.java
index f04202043e..d272c99b98 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/BusUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/BusUtils.java
@@ -16,11 +16,12 @@
 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;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java
index bb48a4b5cf..c5a9a17a6d 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskStaticUtils.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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java
index 67e6b3fb0e..a8ae8afa5b 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDiskUtils.java
@@ -8,9 +8,10 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java
index 2ef267bd01..6dbb9f7475 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleStaticUtils.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java
index c800423c78..aca1c25837 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java
+++ b/utilcode/lib/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;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java
index 56abfba117..aedcfa7fc4 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryStaticUtils.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java
index d0e06e394d..ddaa2baed9 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CacheMemoryUtils.java
+++ b/utilcode/lib/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/utilcode/lib/src/main/java/com/blankj/utilcode/util/ColorUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ColorUtils.java
index 4c0c22232b..a6603cfc44 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ColorUtils.java
+++ b/utilcode/lib/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;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java
index 18b5f814a3..081dd09761 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/CrashUtils.java
@@ -5,8 +5,8 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
 import android.util.Log;
 
 import java.io.BufferedWriter;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java
index e6b1910cfc..c641c9bdae 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/DeviceUtils.java
@@ -11,11 +11,12 @@
 import android.os.Debug;
 import android.os.PowerManager;
 import android.provider.Settings;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RequiresPermission;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
+
 import java.io.File;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java
index 43b8537e75..9e8ae14ef1 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/FragmentUtils.java
@@ -3,16 +3,6 @@
 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;
 
@@ -20,6 +10,17 @@
 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
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java
index 83e01eb1ad..cbee7dd4bd 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ImageUtils.java
@@ -27,13 +27,13 @@
 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 androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.core.content.ContextCompat;
 import android.view.View;
 
 import java.io.BufferedOutputStream;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java
index 6faa37d043..1e26dc8a9a 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/IntentUtils.java
@@ -8,8 +8,8 @@
 import android.os.Bundle;
 import android.provider.MediaStore;
 import android.provider.Settings;
-import android.support.annotation.RequiresPermission;
-import android.support.v4.content.FileProvider;
+import androidx.annotation.RequiresPermission;
+import androidx.core.content.FileProvider;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java
index cfa568fa7c..de3eb285cc 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java
@@ -7,7 +7,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.ResultReceiver;
-import android.support.annotation.NonNull;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -16,6 +15,8 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 
+import androidx.annotation.NonNull;
+
 import java.lang.reflect.Field;
 
 /**
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java
index 1372ecd40b..9a7e11cbf5 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/LogUtils.java
@@ -10,10 +10,10 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.RequiresApi;
-import android.support.v4.util.SimpleArrayMap;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.RequiresApi;
+import androidx.collection.SimpleArrayMap;
 import android.util.Log;
 
 import com.google.gson.Gson;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java
index 6f6cf85b80..bd4b8da935 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java
+++ b/utilcode/lib/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;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java
index d59eb28240..24a05a26b7 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NetworkUtils.java
@@ -7,13 +7,14 @@
 import android.net.NetworkInfo;
 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;
 import java.net.InterfaceAddress;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java
index b8163d2e66..73a900b465 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/NotificationUtils.java
@@ -5,9 +5,9 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.support.annotation.Nullable;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
+import androidx.annotation.Nullable;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java
index be5491ece0..3c0c087a39 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ObjectUtils.java
@@ -1,9 +1,9 @@
 package com.blankj.utilcode.util;
 
 import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.support.v4.util.LongSparseArray;
-import android.support.v4.util.SimpleArrayMap;
+import androidx.annotation.RequiresApi;
+import androidx.collection.LongSparseArray;
+import androidx.collection.SimpleArrayMap;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java
index d35cbcc620..602efcb5db 100755
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PermissionUtils.java
@@ -9,10 +9,10 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.content.ContextCompat;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.WindowManager;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java
index 99068781a4..f407f81b5f 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/PhoneUtils.java
@@ -7,7 +7,7 @@
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresPermission;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java
index adcd265f72..619b175549 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ProcessUtils.java
@@ -10,8 +10,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
 import android.util.Log;
 
 import java.util.Arrays;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java
index ba57fab956..817a94149f 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/RegexUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.v4.util.SimpleArrayMap;
+import androidx.collection.SimpleArrayMap;
 
 import com.blankj.utilcode.constant.RegexConstants;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java
index 81d10f08cf..3fb515c06b 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ResourceUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.RawRes;
+import androidx.annotation.RawRes;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java
index d3e21fb873..21274c3023 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPStaticUtils.java
@@ -1,7 +1,7 @@
 package com.blankj.utilcode.util;
 
 import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import java.util.Map;
 import java.util.Set;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java
index 554a2ed586..a9d18a1a55 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SPUtils.java
@@ -3,7 +3,7 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
index 7390fceed0..3245eb115c 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
@@ -10,8 +10,8 @@
 import android.graphics.Point;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
 import android.util.DisplayMetrics;
 import android.view.Surface;
 import android.view.View;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ShellUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ShellUtils.java
index b7ad2fa9d2..fc10a601ae 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ShellUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ShellUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import java.io.BufferedReader;
 import java.io.DataOutputStream;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java
index b164e6154e..eab1990d29 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java
@@ -1,12 +1,12 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import com.google.android.material.snackbar.Snackbar;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.style.ForegroundColorSpan;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java
index b8d9d53aed..4d49451ec0 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/SpanUtils.java
@@ -14,14 +14,14 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
 import android.text.Layout;
 import android.text.Layout.Alignment;
 import android.text.SpannableStringBuilder;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java
index c3254e3d32..70f0defe50 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/StringUtils.java
@@ -1,8 +1,8 @@
 package com.blankj.utilcode.util;
 
 import android.content.res.Resources;
-import android.support.annotation.ArrayRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.ArrayRes;
+import androidx.annotation.StringRes;
 
 /**
  * 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java
index 0545a27fa0..19de94ca33 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ThreadUtils.java
@@ -2,10 +2,11 @@
 
 import android.os.Handler;
 import android.os.Looper;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
 import android.util.Log;
 
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Executor;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java
index adaa920474..a5286b0fbe 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/TimeUtils.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 import com.blankj.utilcode.constant.TimeConstants;
 
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java
index 150425cdba..0dd47cfa3e 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/ToastUtils.java
@@ -12,11 +12,11 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.StringRes;
-import android.support.v4.app.NotificationManagerCompat;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.StringRes;
+import androidx.core.app.NotificationManagerCompat;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java
index 9ad408912a..20fdc39b81 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/UriUtils.java
@@ -8,12 +8,14 @@
 import android.os.Environment;
 import android.provider.DocumentsContract;
 import android.provider.MediaStore;
-import android.support.annotation.NonNull;
-import android.support.v4.content.FileProvider;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.File;
 
+import androidx.annotation.NonNull;
+import androidx.core.content.FileProvider;
+
 /**
  * 
  *     author: Blankj
@@ -75,12 +77,19 @@ public static File uri2File(@NonNull final Uri uri) {
                 Log.d("UriUtils", uri.toString() + " parse failed. -> 1");
                 return null;
             } else if ("com.android.providers.downloads.documents".equals(authority)) {
-                final String id = DocumentsContract.getDocumentId(uri);
-                final Uri contentUri = ContentUris.withAppendedId(
-                        Uri.parse("content://downloads/public_downloads"),
-                        Long.valueOf(id)
-                );
-                return getFileFromUri(contentUri, 2);
+                String id = DocumentsContract.getDocumentId(uri);
+                if (!TextUtils.isEmpty(id)) {
+                    if (id.startsWith("raw:")) {
+                        return new File(id.substring(4));
+                    }
+                    final Uri contentUri = ContentUris.withAppendedId(
+                            Uri.parse(Environment.DIRECTORY_DOWNLOADS),
+                            Long.valueOf(id)
+                    );
+                    return getFileFromUri(contentUri, 2);
+                }
+                Log.d("UriUtils", uri.toString() + " parse failed. -> 3");
+                return null;
             } else if ("com.android.providers.media.documents".equals(authority)) {
                 final String docId = DocumentsContract.getDocumentId(uri);
                 final String[] split = docId.split(":");
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java
index d0c98afc96..1992a2c902 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/Utils.java
@@ -13,13 +13,14 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.v4.content.FileProvider;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 
+import androidx.core.content.FileProvider;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
diff --git a/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java b/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java
index a57bbb8241..622d657817 100644
--- a/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java
+++ b/utilcode/lib/src/main/java/com/blankj/utilcode/util/VibrateUtils.java
@@ -2,7 +2,7 @@
 
 import android.content.Context;
 import android.os.Vibrator;
-import android.support.annotation.RequiresPermission;
+import androidx.annotation.RequiresPermission;
 
 import static android.Manifest.permission.VIBRATE;
 
diff --git a/utilcode/lib/src/test/java/com/blankj/utilcode/util/BaseTest.java b/utilcode/lib/src/test/java/com/blankj/utilcode/util/BaseTest.java
index 85bc9d8ac2..2dadedff8c 100644
--- a/utilcode/lib/src/test/java/com/blankj/utilcode/util/BaseTest.java
+++ b/utilcode/lib/src/test/java/com/blankj/utilcode/util/BaseTest.java
@@ -1,8 +1,5 @@
 package com.blankj.utilcode.util;
 
-
-import android.support.annotation.NonNull;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
@@ -29,7 +26,7 @@ public BaseTest() {
         ShadowLog.stream = System.out;
         ThreadUtils.setDeliver(new Executor() {
             @Override
-            public void execute(@NonNull Runnable command) {
+            public void execute(Runnable command) {
                 command.run();
             }
         });
@@ -201,8 +198,8 @@ public void onFail(Throwable t) {
     static class Person implements Comparable {
 
         String name;
-        int age;
-        int time;
+        int    age;
+        int    time;
 
         public Person(String name) {
             this.name = name;
@@ -220,7 +217,7 @@ public String toString() {
         }
 
         @Override
-        public int compareTo(@NonNull Person o) {
+        public int compareTo(Person o) {
             int res = o.age - age;
             if (res != 0) {
                 return res;
diff --git a/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java b/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java
index a0203f78fc..ed12c24d8d 100644
--- a/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java
+++ b/utilcode/lib/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java
@@ -1,7 +1,5 @@
 package com.blankj.utilcode.util;
 
-import android.support.v4.util.LongSparseArray;
-import android.support.v4.util.SimpleArrayMap;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
@@ -12,6 +10,9 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 
+import androidx.collection.LongSparseArray;
+import androidx.collection.SimpleArrayMap;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
diff --git a/utilcode/pkg/build.gradle b/utilcode/pkg/build.gradle
index 9fe360a5dd..881637b34a 100644
--- a/utilcode/pkg/build.gradle
+++ b/utilcode/pkg/build.gradle
@@ -4,5 +4,5 @@ apply {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    api project(':lib:base')
+    api gradle.ext.dep.lib_base
 }
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
index e784f98401..9982c948b7 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
@@ -6,7 +6,7 @@ import android.graphics.Bitmap
 import android.graphics.drawable.BitmapDrawable
 import android.os.Build
 import android.os.Bundle
-import android.support.v4.app.ActivityOptionsCompat
+import androidx.core.app.ActivityOptionsCompat
 import android.view.View
 import android.view.Window
 import com.blankj.lib.base.BaseTitleActivity
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
index 0c63773639..abf0151bbc 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
@@ -2,7 +2,7 @@ package com.blankj.utilcode.pkg.feature.activity
 
 import android.os.Build
 import android.os.Bundle
-import android.support.v4.app.ActivityCompat
+import androidx.core.app.ActivityCompat
 import android.view.View
 import android.view.Window
 import com.blankj.lib.base.BaseTitleActivity
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt
index d4f0d60530..fc8020b3e5 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarStatusFragmentActivity.kt
@@ -3,10 +3,10 @@ package com.blankj.utilcode.pkg.feature.bar
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
-import android.support.design.widget.BottomNavigationView
-import android.support.v4.app.Fragment
-import android.support.v4.app.FragmentPagerAdapter
-import android.support.v4.view.ViewPager
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentPagerAdapter
+import androidx.viewpager.widget.ViewPager
 import android.view.View
 import com.blankj.lib.base.BaseActivity
 import com.blankj.utilcode.pkg.R
@@ -37,7 +37,7 @@ class BarStatusFragmentActivity : BaseActivity() {
             R.id.barStatusFragmentNavigationCustom
     )
 
-    private val mFragmentList = ArrayList()
+    private val mFragmentList = ArrayList()
 
     private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener l@{ item ->
         when (item.itemId) {
@@ -78,8 +78,8 @@ class BarStatusFragmentActivity : BaseActivity() {
         mFragmentList.add(BarStatusCustomFragment.newInstance())
 
         barStatusFragmentVp.offscreenPageLimit = 3
-        barStatusFragmentVp.adapter = object : FragmentPagerAdapter(supportFragmentManager) {
-            override fun getItem(position: Int): Fragment {
+        barStatusFragmentVp.adapter = object : androidx.fragment.app.FragmentPagerAdapter(supportFragmentManager) {
+            override fun getItem(position: Int): androidx.fragment.app.Fragment {
                 return mFragmentList[position]
             }
 
@@ -88,7 +88,7 @@ class BarStatusFragmentActivity : BaseActivity() {
             }
         }
 
-        barStatusFragmentVp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
+        barStatusFragmentVp.addOnPageChangeListener(object : androidx.viewpager.widget.ViewPager.OnPageChangeListener {
             override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
 
             override fun onPageSelected(position: Int) {
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
index ada9dd0d10..86972c449d 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
@@ -2,8 +2,8 @@ package com.blankj.utilcode.pkg.feature.fragment
 
 import android.os.Build
 import android.os.Bundle
-import android.support.annotation.RequiresApi
-import android.support.v4.app.Fragment
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.Fragment
 import android.transition.*
 import android.view.View
 import com.blankj.lib.base.BaseLazyFragment
@@ -128,7 +128,7 @@ class ContainerFragment : BaseLazyFragment(), FragmentUtils.OnBackClickListener
         }
     }
 
-    private fun addSharedElement(fragment: Fragment): Fragment {
+    private fun addSharedElement(fragment: androidx.fragment.app.Fragment): androidx.fragment.app.Fragment {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             fragment.sharedElementEnterTransition = DetailTransition()
             fragment.enterTransition = Fade()
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
index 446271b366..b18a2e236b 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
@@ -4,8 +4,8 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.os.PersistableBundle
-import android.support.design.widget.BottomNavigationView
-import android.support.v4.app.Fragment
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import androidx.fragment.app.Fragment
 import android.view.View
 import com.blankj.lib.base.BaseActivity
 import com.blankj.utilcode.pkg.R
@@ -29,7 +29,7 @@ class FragmentActivity : BaseActivity() {
         }
     }
 
-    private val mFragments = arrayListOf()
+    private val mFragments = arrayListOf()
     private var curIndex: Int = 0
 
     private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
index 0e092e0062..2c6656f220 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
@@ -6,12 +6,12 @@ import android.graphics.Bitmap
 import android.graphics.Color
 import android.os.Build
 import android.os.Bundle
-import android.support.annotation.StringRes
-import android.support.v7.widget.LinearLayoutManager
 import android.view.View
 import android.widget.Button
 import android.widget.ImageView
 import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.recyclerview.widget.LinearLayoutManager
 import com.blankj.lib.base.BaseTaskActivity
 import com.blankj.lib.base.rv.BaseAdapter
 import com.blankj.lib.base.rv.BaseCell
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
index a0ea36d528..cd1c1b0d99 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
@@ -4,7 +4,7 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.Color
 import android.os.Bundle
-import android.support.annotation.StringRes
+import androidx.annotation.StringRes
 import android.text.SpannableStringBuilder
 import android.view.View
 import android.view.ViewGroup
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
index d84ced168c..202069ed61 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
@@ -5,7 +5,7 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.*
 import android.os.Bundle
-import android.support.annotation.ColorInt
+import androidx.annotation.ColorInt
 import android.text.Layout
 import android.text.SpannableStringBuilder
 import android.text.TextPaint
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
index 314ba33d59..458ecbb3fb 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
@@ -2,7 +2,7 @@ package com.blankj.utilcode.pkg.feature.toast
 
 import android.os.Handler
 import android.os.Looper
-import android.support.annotation.StringRes
+import androidx.annotation.StringRes
 import android.widget.TextView
 import android.widget.Toast
 
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
index 51c9e53774..47f91e826e 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
@@ -4,7 +4,7 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.Color
 import android.os.Bundle
-import android.support.v4.content.ContextCompat
+import androidx.core.content.ContextCompat
 import android.view.Gravity
 import android.view.View
 import com.blankj.lib.base.BaseTitleActivity
diff --git a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
index 344a69e448..a495a13013 100644
--- a/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
+++ b/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
@@ -3,7 +3,6 @@ package com.blankj.utilcode.pkg.helper
 import android.app.Dialog
 import android.graphics.Bitmap
 import android.graphics.drawable.ColorDrawable
-import android.support.v7.app.AlertDialog
 import android.text.method.ScrollingMovementMethod
 import android.view.Gravity
 import android.view.LayoutInflater
@@ -12,9 +11,9 @@ import android.widget.Button
 import android.widget.EditText
 import android.widget.ImageView
 import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
 import com.blankj.utilcode.pkg.R
 import com.blankj.utilcode.util.*
-import com.blankj.utilcode.util.PermissionUtils.OnRationaleListener.ShouldRequest
 
 /**
  * ```
@@ -26,7 +25,7 @@ import com.blankj.utilcode.util.PermissionUtils.OnRationaleListener.ShouldReques
  */
 object DialogHelper {
 
-    fun showRationaleDialog(shouldRequest: ShouldRequest) {
+    fun showRationaleDialog(shouldRequest: PermissionUtils.OnRationaleListener.ShouldRequest) {
         val topActivity = ActivityUtils.getTopActivity()
         AlertDialog.Builder(topActivity)
                 .setTitle(android.R.string.dialog_alert_title)
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
index 792ae5672e..9be8749952 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
@@ -1,5 +1,5 @@
 
-
 
-
+
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml
index ccc88dddb6..1522b0741b 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_close.xml
@@ -8,7 +8,7 @@
     android:fillViewport="true"
     tools:context=".feature.adaptScreen.AdaptCloseActivity">
 
-    
 
@@ -43,6 +43,6 @@
             android:textSize="30pt"
             app:layout_constraintTop_toBottomOf="@id/adaptScreenCloseAdaptDpTv" />
 
-    
+    
 
 
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml
index 350921b04d..75fa87e8e5 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_height.xml
@@ -1,13 +1,12 @@
 
-
 
-    
 
@@ -94,6 +93,6 @@
                 android:textSize="30pt" />
         
 
-    
+    
 
 
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml
index 121415e1b6..dd9f9f40c7 100644
--- a/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_adaptscreen_width.xml
@@ -8,7 +8,7 @@
     android:fillViewport="true"
     tools:context=".feature.adaptScreen.AdaptWidthActivity">
 
-    
 
@@ -149,6 +149,6 @@
 
         
 
-    
+    
 
 
\ No newline at end of file
diff --git a/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml b/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml
index 3ce196004b..bd6e43e7a7 100644
--- a/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml
+++ b/utilcode/pkg/src/main/res/layout/activity_bar_status_fragment.xml
@@ -6,7 +6,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical">
 
-    
 
-    
 
-    
-
Date: Sat, 29 Jun 2019 19:59:42 +0800
Subject: [PATCH 05/61] see 06/29 log

---
 .../test/java/com/blankj/utilcode/util/TimeUtilsTest.java    | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/utilcode/lib/src/test/java/com/blankj/utilcode/util/TimeUtilsTest.java b/utilcode/lib/src/test/java/com/blankj/utilcode/util/TimeUtilsTest.java
index 2ba0a41586..5ab8ee17eb 100644
--- a/utilcode/lib/src/test/java/com/blankj/utilcode/util/TimeUtilsTest.java
+++ b/utilcode/lib/src/test/java/com/blankj/utilcode/util/TimeUtilsTest.java
@@ -42,15 +42,14 @@ public class TimeUtilsTest  {
     public void millis2String() {
         assertEquals(timeString, TimeUtils.millis2String(timeMillis));
         assertEquals(timeStringFormat, TimeUtils.millis2String(timeMillis, mFormat));
-        assertEquals("2017年05月04日", TimeUtils.millis2String(timeMillis, "yyyy年MM月dd日"));
-        assertEquals("16时37分", TimeUtils.millis2String(timeMillis, "HH时mm分"));
+        assertEquals(timeStringFormat, TimeUtils.millis2String(timeMillis, "yyyy MM dd HH:mm:ss"));
     }
 
     @Test
     public void string2Millis() {
         assertEquals(timeMillis, TimeUtils.string2Millis(timeString));
         assertEquals(timeMillis, TimeUtils.string2Millis(timeStringFormat, mFormat));
-        assertEquals(timeMillis, TimeUtils.string2Millis(timeStringFormat, "yyyy年MM月dd日HH时mm分"));
+        assertEquals(timeMillis, TimeUtils.string2Millis(timeStringFormat, "yyyy MM dd HH:mm:ss"));
     }
 
     @Test

From 40c0e36fbb1dc33ebce09a6fa162e07380271cf9 Mon Sep 17 00:00:00 2001
From: Blankj <625783482@qq.com>
Date: Thu, 15 Aug 2019 01:36:03 +0800
Subject: [PATCH 06/61] see 08/15 log

---
 lib/utilcode/README-CN.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
index d610595e3c..cce78181fc 100644
--- a/lib/utilcode/README-CN.md
+++ b/lib/utilcode/README-CN.md
@@ -1185,7 +1185,7 @@ getComments       : 获取压缩文件中的注释链表
 [log.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt
 
 [map.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/MapUtils.java
-[map.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/test/java/com/blankj/utilcode/util/MapUtilsTest.java
+[map.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/test/java/com/blankj/utilcode/util/MapUtilsTest.java
 
 [metaData.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java
 [metaData.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt

From 73dc60c4cdfa10a2b296df3e28ce9af2784be582 Mon Sep 17 00:00:00 2001
From: Blankj <625783482@qq.com>
Date: Sat, 30 Nov 2019 13:03:30 +0800
Subject: [PATCH 07/61] see 11/30 log

---
 buildSrc/src/main/groovy/Config.groovy                        | 2 +-
 config.json                                                   | 2 +-
 .../pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt     | 2 +-
 .../utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java  | 2 +-
 lib/base/build.gradle                                         | 2 +-
 lib/subutil/build.gradle                                      | 4 ++--
 lib/utildebug/build.gradle                                    | 2 +-
 7 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index 03181d7927..cc279262a8 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -41,7 +41,7 @@ class Config {
             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:1.26.0"),
+            lib_utilcodex              : new DepConfig(true, true, ":lib:utilcodex", "com.blankj:utilcodex:1.26.0"),
             lib_utildebug              : new DepConfig(true, true, ":lib:utildebug", "com.blankj:utildebug:1.25.10-alpha5"),
             lib_utildebug_no_op        : new DepConfig(true, true, ":lib:utildebug-no-op", "com.blankj:utildebug-no-op:1.25.10-alpha5"),
             /*Never delete this line*/
diff --git a/config.json b/config.json
index 188e2ff509..630e76de6a 100644
--- a/config.json
+++ b/config.json
@@ -20,7 +20,7 @@
     {"isApply": true, "useLocal": true, "localPath": ":lib:base"},
     {"isApply": true, "useLocal": true, "localPath": ":lib:common"},
     {"isApply": true, "useLocal": true, "localPath": ":lib:subutil"},
-    {"isApply": true, "useLocal": true, "localPath": ":lib:utilcode", "remotePath": "com.blankj:utilcode:1.26.0"},
+    {"isApply": true, "useLocal": true, "localPath": ":lib:utilcodex", "remotePath": "com.blankj:utilcodex:1.26.0"},
     {"isApply": true, "useLocal": true, "localPath": ":lib:utildebug", "remotePath": "com.blankj:utildebug:1.25.10-alpha5"},
     {"isApply": true, "useLocal": true, "localPath": ":lib:utildebug-no-op", "remotePath": "com.blankj:utildebug-no-op:1.25.10-alpha5"}
   ]
diff --git a/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt b/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt
index fb45369c5b..ccce008ded 100644
--- a/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt
+++ b/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt
@@ -2,8 +2,8 @@ package com.blankj.main.pkg
 
 import android.graphics.Color
 import android.os.Bundle
-import androidx.appcompat.app.ActionBarDrawerToggle
 import android.view.View
+import androidx.appcompat.app.ActionBarDrawerToggle
 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/reflect/TestPrivateStaticFinal.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java
index e62c518699..b7efb5f4d7 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.pkg.feature.reflect;
 
-import android.support.annotation.Keep;
+import androidx.annotation.Keep;
 
 /**
  * 
diff --git a/lib/base/build.gradle b/lib/base/build.gradle
index 2285071b5e..6fffd3af61 100644
--- a/lib/base/build.gradle
+++ b/lib/base/build.gradle
@@ -1,7 +1,7 @@
 dependencies {
     implementation fileTree(include: ['*.jar'], dir: 'libs')
     api Config.depConfig.lib_subutil.dep
-    api Config.depConfig.lib_utilcode.dep
+    api Config.depConfig.lib_utilcodex.dep
 
     api Config.depConfig.support_appcompat.dep
     api Config.depConfig.support_material.dep
diff --git a/lib/subutil/build.gradle b/lib/subutil/build.gradle
index 662f2a4ec7..e7eaf45da1 100644
--- a/lib/subutil/build.gradle
+++ b/lib/subutil/build.gradle
@@ -13,14 +13,14 @@ readme {
 dependencies {
     compileOnly Config.depConfig.support_appcompat.dep
     compileOnly Config.depConfig.support_material.dep
-    compileOnly Config.depConfig.lib_utilcode.dep
+    compileOnly Config.depConfig.lib_utilcodex.dep
     api(Config.depConfig.glide.dep) {
         exclude group: "com.android.support"
     }
     api Config.depConfig.retrofit.dep
     api Config.depConfig.gson.dep
 
-    testImplementation Config.depConfig.lib_utilcode.dep
+    testImplementation Config.depConfig.lib_utilcodex.dep
     testImplementation Config.depConfig.test_junit.dep
     testImplementation Config.depConfig.test_robolectric.dep
 }
\ No newline at end of file
diff --git a/lib/utildebug/build.gradle b/lib/utildebug/build.gradle
index b6380100bb..558735162a 100644
--- a/lib/utildebug/build.gradle
+++ b/lib/utildebug/build.gradle
@@ -5,7 +5,7 @@ apply {
 }
 
 dependencies {
-    implementation Config.depConfig.lib_utilcode.dep
+    implementation Config.depConfig.lib_utilcodex.dep
     implementation Config.depConfig.swipe_panel.dep
     implementation Config.depConfig.photo_view.dep
     compileOnly Config.depConfig.support_appcompat.dep

From 3fd7a91e0e3bbd2ddbaf2b79163527b02dcc87d9 Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Tue, 7 Apr 2020 00:11:37 +0800
Subject: [PATCH 08/61] see 04/07 log

---
 lib/utildebug/build.gradle | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/utildebug/build.gradle b/lib/utildebug/build.gradle
index b733473cf1..6e1157ef0b 100644
--- a/lib/utildebug/build.gradle
+++ b/lib/utildebug/build.gradle
@@ -9,4 +9,8 @@ dependencies {
     testImplementation Config.depConfig.test_junit.dep
     testImplementation Config.depConfig.test_robolectric.dep
     testImplementation Config.depConfig.support_appcompat.dep
+}
+
+afterEvaluate {
+    verifyReleaseResources.enabled(false)
 }
\ No newline at end of file

From 96c45acb8eb47a58c84bb467e6b126500765f5b2 Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Tue, 7 Apr 2020 17:21:35 +0800
Subject: [PATCH 09/61] see 04/07 log

---
 .../src/test/java/com/blankj/utilcode/util/BaseTest.java  | 8 +++++---
 .../java/com/blankj/utilcode/util/UiMessageUtilsTest.java | 3 ++-
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/utilcode/src/test/java/com/blankj/utilcode/util/BaseTest.java b/lib/utilcode/src/test/java/com/blankj/utilcode/util/BaseTest.java
index 6e097938bf..ebaa83564d 100644
--- a/lib/utilcode/src/test/java/com/blankj/utilcode/util/BaseTest.java
+++ b/lib/utilcode/src/test/java/com/blankj/utilcode/util/BaseTest.java
@@ -1,7 +1,5 @@
 package com.blankj.utilcode.util;
 
-import android.support.annotation.NonNull;
-import java.util.concurrent.Executor;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
@@ -9,6 +7,10 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowLog;
 
+import java.util.concurrent.Executor;
+
+import androidx.annotation.NonNull;
+
 /**
  * 
  *     author: Blankj
@@ -18,7 +20,7 @@
  * 
*/ @RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE,shadows = { ShadowLog.class }) +@Config(manifest = Config.NONE, shadows = {ShadowLog.class}) public class BaseTest { @BusUtils.Bus(tag = "base") diff --git a/lib/utilcode/src/test/java/com/blankj/utilcode/util/UiMessageUtilsTest.java b/lib/utilcode/src/test/java/com/blankj/utilcode/util/UiMessageUtilsTest.java index 1ef00ee586..140dd77683 100644 --- a/lib/utilcode/src/test/java/com/blankj/utilcode/util/UiMessageUtilsTest.java +++ b/lib/utilcode/src/test/java/com/blankj/utilcode/util/UiMessageUtilsTest.java @@ -1,9 +1,10 @@ package com.blankj.utilcode.util; -import android.support.annotation.NonNull; import org.junit.Test; +import androidx.annotation.NonNull; + /** *
  *     author: blankj

From 7145da0408a6f5ed8f0bbd531245750eb1a1c75d Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Tue, 5 May 2020 02:24:34 +0800
Subject: [PATCH 10/61] see 05/05 log

---
 buildSrc/src/main/groovy/Config.groovy | 8 ++++----
 lib/base/build.gradle                  | 8 ++++----
 lib/subutil/build.gradle               | 4 ++--
 lib/utilcode/build.gradle              | 8 ++++----
 lib/utildebug/build.gradle             | 6 +++---
 5 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index d8e41b3ca2..88b8eb9a5a 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -60,10 +60,10 @@ class Config {
             //./gradlew clean plugin:plugin_bus-gradle-plugin:mavenLocal     // 上传到本地 mavenLocal
             //./gradlew clean plugin:plugin_bus-gradle-plugin:bintrayUpload  // 上传到 jcenter
 
-            support_appcompat          : new DepConfig("androidx.appcompat:appcompat:$androidxVersion"),
-            support_material           : new DepConfig("com.google.android.material:material:$androidxVersion"),
-            support_multidex           : new DepConfig("com.android.support:multidex:1.0.2"),
-            support_constraint         : new DepConfig("com.android.support.constraint:constraint-layout:1.1.3"),
+            androidx_appcompat          : new DepConfig("androidx.appcompat:appcompat:$androidxVersion"),
+            androidx_material           : new DepConfig("com.google.android.material:material:$androidxVersion"),
+            androidx_multidex           : new DepConfig("androidx.multidex:multidex:2.0.0"),
+            androidx_constraint         : new DepConfig("androidx.constraintlayout:constraintlayout:1.1.3"),
 
             kotlin                     : new DepConfig("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"),
 
diff --git a/lib/base/build.gradle b/lib/base/build.gradle
index 9a1ac7b329..bb7fa31573 100644
--- a/lib/base/build.gradle
+++ b/lib/base/build.gradle
@@ -3,10 +3,10 @@ dependencies {
     api Config.depConfig.lib_subutil.dep
     api Config.depConfig.lib_utilcode.dep
 
-    api Config.depConfig.support_appcompat.dep
-    api Config.depConfig.support_material.dep
-    api Config.depConfig.support_multidex.dep
-    api Config.depConfig.support_constraint.dep
+    api Config.depConfig.androidx_appcompat.dep
+    api Config.depConfig.androidx_material.dep
+    api Config.depConfig.androidx_multidex.dep
+    api Config.depConfig.androidx_constraint.dep
     api Config.depConfig.kotlin.dep
     api Config.depConfig.free_proguard.dep
     api Config.depConfig.swipe_panel.dep
diff --git a/lib/subutil/build.gradle b/lib/subutil/build.gradle
index a8798fea1b..a561916f3e 100644
--- a/lib/subutil/build.gradle
+++ b/lib/subutil/build.gradle
@@ -9,8 +9,8 @@ readme {
 }
 
 dependencies {
-    compileOnly Config.depConfig.support_appcompat.dep
-    compileOnly Config.depConfig.support_material.dep
+    compileOnly Config.depConfig.androidx_appcompat.dep
+    compileOnly Config.depConfig.androidx_material.dep
     compileOnly Config.depConfig.lib_utilcode.dep
     api(Config.depConfig.glide.dep) {
         exclude group: "com.android.support"
diff --git a/lib/utilcode/build.gradle b/lib/utilcode/build.gradle
index a3ed94861c..891f7dbf40 100644
--- a/lib/utilcode/build.gradle
+++ b/lib/utilcode/build.gradle
@@ -29,13 +29,13 @@ android {
 dependencies {
     implementation Config.depConfig.gson.dep
 
-    compileOnly Config.depConfig.support_appcompat.dep
-    compileOnly Config.depConfig.support_material.dep
+    compileOnly Config.depConfig.androidx_appcompat.dep
+    compileOnly Config.depConfig.androidx_material.dep
 
     testImplementation Config.depConfig.test_junit.dep
     testImplementation Config.depConfig.test_robolectric.dep
-    testImplementation Config.depConfig.support_appcompat.dep
-    testImplementation Config.depConfig.support_material.dep
+    testImplementation Config.depConfig.androidx_appcompat.dep
+    testImplementation Config.depConfig.androidx_material.dep
     testImplementation Config.depConfig.eventbus_lib.dep
 }
 
diff --git a/lib/utildebug/build.gradle b/lib/utildebug/build.gradle
index 6e1157ef0b..82b55495b0 100644
--- a/lib/utildebug/build.gradle
+++ b/lib/utildebug/build.gradle
@@ -1,6 +1,6 @@
 dependencies {
-    compileOnly Config.depConfig.support_appcompat.dep
-    compileOnly Config.depConfig.support_material.dep
+    compileOnly Config.depConfig.androidx_appcompat.dep
+    compileOnly Config.depConfig.androidx_material.dep
 
     implementation Config.depConfig.lib_utilcode.dep
     implementation Config.depConfig.swipe_panel.dep
@@ -8,7 +8,7 @@ dependencies {
 
     testImplementation Config.depConfig.test_junit.dep
     testImplementation Config.depConfig.test_robolectric.dep
-    testImplementation Config.depConfig.support_appcompat.dep
+    testImplementation Config.depConfig.androidx_appcompat.dep
 }
 
 afterEvaluate {

From c7190639ec44b9ff4b5b35f5580458b77abd79c7 Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Tue, 5 May 2020 02:26:00 +0800
Subject: [PATCH 11/61] see 05/05 log

---
 buildApp.gradle                        |  2 +-
 buildSrc/src/main/groovy/Config.groovy | 12 ++++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/buildApp.gradle b/buildApp.gradle
index 2220ed6947..8cb7de95fe 100644
--- a/buildApp.gradle
+++ b/buildApp.gradle
@@ -68,7 +68,7 @@ android {
 
 dependencies {
     // LeakCanary
-    debugImplementation Config.depConfig.leakcanary_android.dep
+    debugImplementation Config.depConfig.leakcanary.dep
 
     debugImplementation Config.depConfig.lib_utildebug.dep
     releaseImplementation Config.depConfig.lib_utildebug_no_op.dep
diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index 88b8eb9a5a..6074cf4d2e 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -20,7 +20,7 @@ class Config {
     // lib version
     static gradlePluginVersion = '3.5.2'
     static kotlinVersion = '1.3.50'
-    static androidxVersion = '1.0.0'
+    static androidxVersion = '1.1.0'
 
     static depConfig = [
             /*Never delete this line*/
@@ -60,14 +60,14 @@ class Config {
             //./gradlew clean plugin:plugin_bus-gradle-plugin:mavenLocal     // 上传到本地 mavenLocal
             //./gradlew clean plugin:plugin_bus-gradle-plugin:bintrayUpload  // 上传到 jcenter
 
-            androidx_appcompat          : new DepConfig("androidx.appcompat:appcompat:$androidxVersion"),
-            androidx_material           : new DepConfig("com.google.android.material:material:$androidxVersion"),
-            androidx_multidex           : new DepConfig("androidx.multidex:multidex:2.0.0"),
-            androidx_constraint         : new DepConfig("androidx.constraintlayout:constraintlayout:1.1.3"),
+            androidx_appcompat         : new DepConfig("androidx.appcompat:appcompat:$androidxVersion"),
+            androidx_material          : new DepConfig("com.google.android.material:material:$androidxVersion"),
+            androidx_multidex          : new DepConfig("androidx.multidex:multidex:2.0.0"),
+            androidx_constraint        : new DepConfig("androidx.constraintlayout:constraintlayout:1.1.3"),
 
             kotlin                     : new DepConfig("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"),
 
-            leakcanary_android         : new DepConfig("com.squareup.leakcanary:leakcanary-android:2.1"),
+            leakcanary                 : new DepConfig("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"),

From e84d6294fdd2a9462072c3564f387fdb51de9e78 Mon Sep 17 00:00:00 2001
From: limuyang 
Date: Mon, 12 Oct 2020 11:57:27 +0800
Subject: [PATCH 12/61] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E4=BF=9D?=
 =?UTF-8?q?=E5=AD=98=E5=9B=BE=E7=89=87=E6=97=B6=E7=9A=84=E5=AE=89=E5=85=A8?=
 =?UTF-8?q?=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/blankj/utilcode/util/ImageUtils.java | 7 +++++++
 1 file changed, 7 insertions(+)

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 f3222ad8f3..7b50da20d6 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
@@ -1709,6 +1709,7 @@ public static File save2Album(final Bitmap src,
                 contentUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
             }
             contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/" + Utils.getApp().getPackageName());
+            contentValues.put(MediaStore.Video.Media.IS_PENDING, 1);
             Uri uri = Utils.getApp().getContentResolver().insert(contentUri, contentValues);
             if (uri == null) {
                 return null;
@@ -1717,8 +1718,14 @@ public static File save2Album(final Bitmap src,
             try {
                 os = Utils.getApp().getContentResolver().openOutputStream(uri);
                 src.compress(format, quality, os);
+
+                contentValues.clear();
+                contentValues.put(MediaStore.Video.Media.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 {

From 42982c4cb36f353c91fe822d0cbc562dd74a3c52 Mon Sep 17 00:00:00 2001
From: limuyang 
Date: Mon, 12 Oct 2020 12:47:11 +0800
Subject: [PATCH 13/61] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E4=BF=9D?=
 =?UTF-8?q?=E5=AD=98=E5=9B=BE=E7=89=87=E6=97=B6=E7=9A=84=E5=AE=89=E5=85=A8?=
 =?UTF-8?q?=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/blankj/utilcode/util/ImageUtils.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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 7b50da20d6..9e27fbde73 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
@@ -1709,7 +1709,7 @@ public static File save2Album(final Bitmap src,
                 contentUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
             }
             contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/" + Utils.getApp().getPackageName());
-            contentValues.put(MediaStore.Video.Media.IS_PENDING, 1);
+            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
             Uri uri = Utils.getApp().getContentResolver().insert(contentUri, contentValues);
             if (uri == null) {
                 return null;
@@ -1720,7 +1720,7 @@ public static File save2Album(final Bitmap src,
                 src.compress(format, quality, os);
 
                 contentValues.clear();
-                contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
+                contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
                 Utils.getApp().getContentResolver().update(uri, contentValues, null, null);
 
                 return UtilsBridge.uri2File(uri);

From 538d76c9c8b1753f4114276bc0a04e60ed08c5ac Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Sun, 25 Oct 2020 02:33:15 +0800
Subject: [PATCH 14/61] see 10/25 log

---
 CHANGELOG.md                                  |   9 +-
 buildSrc/src/main/groovy/Config.groovy        |   4 +-
 .../com/blankj/launcher/app/LauncherApp.java  |   8 -
 .../feature/dangerous/DangerousActivity.kt    |  16 +-
 .../pkg/feature/location/LocationActivity.kt  |  43 +-
 .../utilcode/pkg/src/main/AndroidManifest.xml |  13 +-
 .../utilcode/pkg/feature/CoreUtilActivity.kt  |  13 +
 .../utilcode/pkg/feature/api/ApiActivity.kt   |   4 +-
 .../utilcode/pkg/feature/app/AppActivity.kt   |   2 +-
 .../pkg/feature/bar/nav/BarNavActivity.kt     |  16 +-
 .../feature/bar/status/BarStatusActivity.kt   |  16 +-
 .../bar/status/BarStatusActivityAlpha.kt      |  10 +-
 .../bar/status/BarStatusActivityDrawer.kt     |  55 +-
 .../bar/status/BarStatusActivityImageView.kt  |  10 +-
 .../status/fragment/BarStatusFragmentAlpha.kt |  10 +-
 .../fragment/BarStatusFragmentImageView.kt    |  10 +-
 .../feature/brightness/BrightnessActivity.kt  |  28 +-
 .../feature/clipboard/ClipboardActivity.kt    |  76 ++
 .../feature/flashlight/FlashlightActivity.kt  |   8 +-
 .../pkg/feature/image/ImageActivity.kt        |  94 ++-
 .../pkg/feature/language/LanguageActivity.kt  |  39 +-
 .../utilcode/pkg/feature/log/LogActivity.kt   |  70 +-
 .../pkg/feature/metaData/MetaDataActivity.kt  |   4 +-
 .../utilcode/pkg/feature/mvp/MvpView.java     |  27 +-
 .../pkg/feature/network/NetworkActivity.kt    |   6 +-
 .../feature/permission/PermissionActivity.kt  |  79 +-
 .../pkg/feature/screen/ScreenActivity.kt      |  24 +-
 .../utilcode/pkg/feature/toast/CustomToast.kt |  51 +-
 .../pkg/feature/toast/ToastActivity.kt        |  66 +-
 .../pkg/feature/volume/VolumeActivity.kt      |  63 ++
 .../pkg/src/main/res/layout/mvp_activity.xml  |  13 +
 .../src/main/res/values-en-rUS/strings.xml    |   4 +-
 .../src/main/res/values-zh-rCN/strings.xml    |  10 +-
 .../pkg/src/main/res/values/strings.xml       |  18 +-
 .../java/com/blankj/base/BaseApplication.java |   7 +-
 .../com/blankj/base/mvp/BasePresenter.java    |   4 +-
 .../common/activity/CommonActivity.java       |   7 +
 .../blankj/common/helper/PermissionHelper.kt  |  16 +-
 .../blankj/common/item/CommonItemSeekBar.java |  47 +-
 lib/subutil/README-CN.md                      |  13 -
 lib/subutil/README.md                         |  13 -
 .../blankj/subutil/util/AppStoreUtils.java    |  36 +-
 .../blankj/subutil/util/ClipboardUtils.java   |  96 ---
 .../blankj/subutil/util/DangerousUtils.java   |   2 +-
 .../com/blankj/subutil/util/HttpsUtil.java    |   6 +-
 .../subutil/util/ClipboardUtilsTest.java      |  50 --
 .../com/blankj/subutil/util/TestUtils.java    |  31 -
 lib/utilcode/README-CN.md                     | 171 ++--
 lib/utilcode/README.md                        |  92 ++-
 .../constant/PermissionConstants.java         |  48 +-
 .../blankj/utilcode/util/ActivityUtils.java   |  18 +
 .../utilcode/util/AdaptScreenUtils.java       |   3 +-
 .../com/blankj/utilcode/util/AppUtils.java    |   3 +-
 .../com/blankj/utilcode/util/BarUtils.java    |   7 +-
 .../com/blankj/utilcode/util/BusUtils.java    |   6 +-
 .../blankj/utilcode/util/ClipboardUtils.java  | 109 +++
 .../com/blankj/utilcode/util/CrashUtils.java  |  53 +-
 .../blankj/utilcode/util/DebouncingUtils.java |   3 -
 .../blankj/utilcode/util/EncryptUtils.java    |  19 +-
 .../blankj/utilcode/util/FlashlightUtils.java |   2 +-
 .../com/blankj/utilcode/util/ImageUtils.java  | 174 +++-
 .../com/blankj/utilcode/util/JsonUtils.java   |   6 +-
 .../blankj/utilcode/util/KeyboardUtils.java   |   2 +-
 .../blankj/utilcode/util/LanguageUtils.java   | 319 ++++---
 .../com/blankj/utilcode/util/LogUtils.java    | 173 ++--
 .../blankj/utilcode/util/MessengerUtils.java  |   6 +-
 .../blankj/utilcode/util/NetworkUtils.java    |   5 +-
 .../blankj/utilcode/util/PermissionUtils.java | 100 ++-
 .../com/blankj/utilcode/util/ScreenUtils.java |  27 +-
 .../com/blankj/utilcode/util/StringUtils.java |  43 +-
 .../com/blankj/utilcode/util/ToastUtils.java  | 777 ++++++++++++------
 .../util/UtilsActivityLifecycleImpl.java      | 164 ++--
 .../com/blankj/utilcode/util/UtilsBridge.java | 145 +++-
 .../utilcode/util/UtilsTransActivity.java     |   4 +-
 .../com/blankj/utilcode/util/ViewUtils.java   |   9 +
 .../com/blankj/utilcode/util/VolumeUtils.java | 120 +++
 .../{toast_frame.xml => utils_toast_bg.xml}   |   1 -
 .../src/main/res/layout/toast_layout.xml      |  23 -
 .../src/main/res/layout/utils_toast_view.xml  |  72 ++
 .../java/com/blankj/utildebug/DebugUtils.java |   5 +
 .../utildebug/base/view/SwipeRightMenu.java   |   4 +-
 81 files changed, 2500 insertions(+), 1460 deletions(-)
 create mode 100644 feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt
 create mode 100644 feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt
 delete mode 100644 lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
 delete mode 100644 lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
 delete mode 100644 lib/subutil/src/test/java/com/blankj/subutil/util/TestUtils.java
 create mode 100644 lib/utilcode/src/main/java/com/blankj/utilcode/util/ClipboardUtils.java
 create mode 100644 lib/utilcode/src/main/java/com/blankj/utilcode/util/VolumeUtils.java
 rename lib/utilcode/src/main/res/drawable/{toast_frame.xml => utils_toast_bg.xml} (79%)
 delete mode 100644 lib/utilcode/src/main/res/layout/toast_layout.xml
 create mode 100644 lib/utilcode/src/main/res/layout/utils_toast_view.xml

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a20bd884ef..f418e68ab7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,11 @@
-* `20/09/06` [add] DebouncingUtils.
+* `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.
diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index 2c85babdf5..d292b40954 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -14,8 +14,8 @@ class Config {
     static compileSdkVersion = 29
     static minSdkVersion = 14
     static targetSdkVersion = 29
-    static versionCode = 1_029_000
-    static versionName = '1.29.0'// E.g. 1.9.72 => 1,009,072
+    static versionCode = 1_030_000
+    static versionName = '1.30.0'// E.g. 1.9.72 => 1,009,072
 
     // lib version
     static gradlePluginVersion = '3.5.0'
diff --git a/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java b/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java
index 0aa8be0786..7dc22cee69 100644
--- a/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java
+++ b/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java
@@ -1,9 +1,6 @@
 package com.blankj.launcher.app;
 
-import android.content.Context;
-
 import com.blankj.common.CommonApplication;
-import com.blankj.utilcode.util.ResourceUtils;
 
 /**
  * 
@@ -21,11 +18,6 @@ public static LauncherApp getInstance() {
         return sInstance;
     }
 
-    @Override
-    protected void attachBaseContext(Context base) {
-        super.attachBaseContext(base);
-    }
-
     @Override
     public void onCreate() {
         super.onCreate();
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
index 8e0183c991..cc5c60f470 100644
--- a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
@@ -87,13 +87,15 @@ class DangerousActivity : CommonActivity() {
                 CommonItemClick(R.string.dangerous_reboot_to_bootloader) {
                     ToastUtils.showShort(DangerousUtils.reboot2Bootloader().toString())
                 },
-                CommonItemSwitch(R.string.dangerous_data_enabled, Utils.Supplier {
-                    NetworkUtils.getMobileDataEnabled()
-                }, Utils.Consumer {
-                    if (AppUtils.isAppSystem()) {
-                        DangerousUtils.setMobileDataEnabled(it)
-                    }
-                }),
+                CommonItemSwitch(
+                        R.string.dangerous_data_enabled,
+                        { NetworkUtils.getMobileDataEnabled() },
+                        {
+                            if (AppUtils.isAppSystem()) {
+                                DangerousUtils.setMobileDataEnabled(it)
+                            }
+                        }
+                ),
                 CommonItemClick(R.string.dangerous_send_sms_silent) {
                     DangerousUtils.sendSmsSilent("10000", "sendSmsSilent")
                 }
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
index 88e55b23f2..8f4217c96c 100755
--- a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
@@ -24,6 +24,14 @@ import com.blankj.utilcode.util.PermissionUtils
  */
 class LocationActivity : CommonActivity() {
 
+    private var lastLatitude: String = "unknown"
+    private var lastLongitude: String = "unknown"
+    private var latitude: String = "unknown"
+    private var longitude: String = "unknown"
+    private var country: String = "unknown"
+    private var locality: String = "unknown"
+    private var street: String = "unknown"
+
     companion object {
         fun start(context: Context) {
             PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
@@ -48,18 +56,17 @@ class LocationActivity : CommonActivity() {
             mLocationService.setOnGetLocationListener(object : LocationService.OnGetLocationListener {
                 override fun getLocation(lastLatitude: String, lastLongitude: String, latitude: String,
                                          longitude: String, country: String, locality: String, street: String) {
+                    this@LocationActivity.apply {
+                        this.lastLatitude = lastLatitude
+                        this.lastLongitude = lastLongitude
+                        this.latitude = latitude
+                        this.longitude = longitude
+                        this.country = country
+                        this.locality = locality
+                        this.street = street
+                    }
                     runOnUiThread {
-                        itemsView.updateItems(
-                                CollectionUtils.newArrayList>(
-                                        CommonItemTitle("lastLatitude", lastLatitude),
-                                        CommonItemTitle("lastLongitude", lastLongitude),
-                                        CommonItemTitle("latitude", latitude),
-                                        CommonItemTitle("longitude", longitude),
-                                        CommonItemTitle("getCountryName", country),
-                                        CommonItemTitle("getLocality", locality),
-                                        CommonItemTitle("getStreet", street)
-                                )
-                        )
+                        itemsView.updateItems(bindItems())
                     }
                 }
             })
@@ -72,13 +79,13 @@ class LocationActivity : CommonActivity() {
 
     override fun bindItems(): MutableList> {
         return CollectionUtils.newArrayList(
-                CommonItemTitle("lastLatitude", "unknown"),
-                CommonItemTitle("lastLongitude", "unknown"),
-                CommonItemTitle("latitude", "unknown"),
-                CommonItemTitle("longitude", "unknown"),
-                CommonItemTitle("getCountryName", "unknown"),
-                CommonItemTitle("getLocality", "unknown"),
-                CommonItemTitle("getStreet", "unknown")
+                CommonItemTitle("lastLatitude", lastLatitude),
+                CommonItemTitle("lastLongitude", lastLongitude),
+                CommonItemTitle("latitude", latitude),
+                CommonItemTitle("longitude", longitude),
+                CommonItemTitle("getCountryName", country),
+                CommonItemTitle("getLocality", locality),
+                CommonItemTitle("getStreet", street)
         )
     }
 
diff --git a/feature/utilcode/pkg/src/main/AndroidManifest.xml b/feature/utilcode/pkg/src/main/AndroidManifest.xml
index fde82401a1..f77ad3d953 100644
--- a/feature/utilcode/pkg/src/main/AndroidManifest.xml
+++ b/feature/utilcode/pkg/src/main/AndroidManifest.xml
@@ -139,6 +139,10 @@
             android:name=".feature.click.ClickActivity"
             android:configChanges="orientation|keyboardHidden|screenSize"
             android:launchMode="singleTop" />
+        
         
             
+                android:value="D1234567890123456789012345678901234567890" />
         
         
         
+            android:configChanges="orientation|keyboardHidden|screenSize" />
         
+        
 
         > {
+    override fun bindItems(): MutableList> {
         return CollectionUtils.newArrayList(
                 CommonItemClick(R.string.api_invoke_with_params) {
                     ApiUtils.getApi(OtherModuleApi::class.java).invokeWithParams(OtherModuleApi.ApiBean("params"))
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
index f835845e6f..7e6f10785a 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
@@ -52,7 +52,7 @@ class AppActivity : CommonActivity() {
         LogUtils.e(requestCode, resultCode)
     }
 
-    override fun bindItems(): List> {
+    override fun bindItems(): MutableList> {
         return CollectionUtils.newArrayList(
                 CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()),
                 CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()),
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
index 997f83f78a..1b3032974f 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
@@ -42,22 +42,14 @@ class BarNavActivity : CommonActivity() {
             if (BarUtils.isSupportNavBar()) {
                 add(CommonItemSwitch(
                         R.string.bar_nav_visibility,
-                        Utils.Supplier {
-                            BarUtils.isNavBarVisible(this@BarNavActivity)
-                        },
-                        Utils.Consumer {
-                            BarUtils.setNavBarVisibility(this@BarNavActivity, it)
-                        }
+                        { BarUtils.isNavBarVisible(this@BarNavActivity) },
+                        { BarUtils.setNavBarVisibility(this@BarNavActivity, it) }
                 ))
 
                 add(CommonItemSwitch(
                         R.string.bar_nav_light_mode,
-                        Utils.Supplier {
-                            BarUtils.isNavBarLightMode(this@BarNavActivity)
-                        },
-                        Utils.Consumer {
-                            BarUtils.setNavBarLightMode(this@BarNavActivity, it)
-                        }
+                        { BarUtils.isNavBarLightMode(this@BarNavActivity) },
+                        { BarUtils.setNavBarLightMode(this@BarNavActivity, it) }
                 ))
 
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt
index 557de0a65a..da20870e79 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt
@@ -37,21 +37,13 @@ class BarStatusActivity : CommonActivity() {
                 CommonItemTitle("getStatusBarHeight", BarUtils.getStatusBarHeight().toString()),
                 CommonItemSwitch(
                         R.string.bar_status_visibility,
-                        Utils.Supplier {
-                            BarUtils.isStatusBarVisible(this)
-                        },
-                        Utils.Consumer {
-                            BarUtils.setStatusBarVisibility(this, it)
-                        }
+                        { BarUtils.isStatusBarVisible(this) },
+                        { BarUtils.setStatusBarVisibility(this, it) }
                 ),
                 CommonItemSwitch(
                         R.string.bar_status_light_mode,
-                        Utils.Supplier {
-                            BarUtils.isStatusBarLightMode(this)
-                        },
-                        Utils.Consumer {
-                            BarUtils.setStatusBarLightMode(this, it)
-                        }
+                        { BarUtils.isStatusBarLightMode(this) },
+                        { BarUtils.setStatusBarLightMode(this, it) }
                 )
         )
     }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt
index b7464443bd..fa886e5be5 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt
@@ -45,15 +45,15 @@ class BarStatusActivityAlpha : CommonActivity() {
 
     private fun getItems(): List> {
         return CollectionUtils.newArrayList>(
-                CommonItemSeekBar("Status Bar Alpha", 255, mAlpha, object : SeekBar.OnSeekBarChangeListener {
+                CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+                    override fun getCurValue(): Int {
+                        return mAlpha
+                    }
+
                     override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                         mAlpha = progress
                         updateStatusBar()
                     }
-
-                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                 }).apply {
                     backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 0.5f)
                 }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt
index 348d349991..d8e092d466 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt
@@ -15,7 +15,6 @@ import com.blankj.utilcode.pkg.R
 import com.blankj.utilcode.util.BarUtils
 import com.blankj.utilcode.util.CollectionUtils
 import com.blankj.utilcode.util.ColorUtils
-import com.blankj.utilcode.util.Utils
 import kotlinx.android.synthetic.main.bar_status_drawer_activity.*
 
 
@@ -61,37 +60,43 @@ class BarStatusActivityDrawer : CommonActivity() {
             return@setOnClickUpdateContentListener ColorUtils.int2ArgbString(mColor)
         }
 
-        val alphaItem: CommonItem<*> = CommonItemSeekBar("Status Bar Alpha", 255, mAlpha, object : SeekBar.OnSeekBarChangeListener {
+        val alphaItem: CommonItem<*> = CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+            override fun getCurValue(): Int {
+                return mAlpha
+            }
+
             override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                 mAlpha = progress
                 updateStatusBar()
             }
-
-            override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
         })
 
         return CollectionUtils.newArrayList(
-                CommonItemSwitch(R.string.bar_status_title_alpha, Utils.Supplier {
-                    updateStatusBar()
-                    return@Supplier mAlphaStatus
-                }, Utils.Consumer {
-                    mAlphaStatus = it
-                    if (mAlphaStatus) {
-                        barStatusDrawerRootLl.setBackgroundResource(R.drawable.image_lena)
-                        commonItemAdapter.replaceItem(2, alphaItem, true)
-                    } else {
-                        barStatusDrawerRootLl.setBackgroundColor(Color.TRANSPARENT)
-                        commonItemAdapter.replaceItem(2, randomColorItem, true)
-                    }
-                }),
-                CommonItemSwitch(R.string.bar_status_is_front, Utils.Supplier {
-                    return@Supplier mFrontStatus
-                }, Utils.Consumer {
-                    mFrontStatus = it
-                    updateStatusBar()
-                }),
+                CommonItemSwitch(
+                        R.string.bar_status_title_alpha,
+                        {
+                            updateStatusBar()
+                            mAlphaStatus
+                        },
+                        {
+                            mAlphaStatus = it
+                            if (mAlphaStatus) {
+                                barStatusDrawerRootLl.setBackgroundResource(R.drawable.image_lena)
+                                commonItemAdapter.replaceItem(2, alphaItem, true)
+                            } else {
+                                barStatusDrawerRootLl.setBackgroundColor(Color.TRANSPARENT)
+                                commonItemAdapter.replaceItem(2, randomColorItem, true)
+                            }
+                        }
+                ),
+                CommonItemSwitch(
+                        R.string.bar_status_is_front,
+                        { mFrontStatus },
+                        {
+                            mFrontStatus = it
+                            updateStatusBar()
+                        }
+                ),
                 randomColorItem
         )
     }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt
index 533a40d7f5..86542caec5 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt
@@ -44,15 +44,15 @@ class BarStatusActivityImageView : CommonActivity() {
 
     private fun getItems(): List> {
         return CollectionUtils.newArrayList>(
-                CommonItemSeekBar("Status Bar Alpha", 255, mAlpha, object : SeekBar.OnSeekBarChangeListener {
+                CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+                    override fun getCurValue(): Int {
+                        return mAlpha
+                    }
+
                     override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                         mAlpha = progress
                         updateStatusBar()
                     }
-
-                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                 })
         )
     }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt
index 15797fc505..ab368c0295 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt
@@ -47,15 +47,15 @@ class BarStatusFragmentAlpha : CommonFragment() {
 
     private fun getItems(): List> {
         return CollectionUtils.newArrayList>(
-                CommonItemSeekBar("Status Bar Alpha", 255, mAlpha, object : SeekBar.OnSeekBarChangeListener {
+                CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+                    override fun getCurValue(): Int {
+                        return mAlpha
+                    }
+
                     override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                         mAlpha = progress
                         updateFakeStatusBar()
                     }
-
-                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                 }).apply {
                     backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 0.5f)
                 }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt
index 54571b6ddd..686e50995c 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt
@@ -46,15 +46,15 @@ class BarStatusFragmentImageView : CommonFragment() {
 
     private fun getItems(): List> {
         return CollectionUtils.newArrayList>(
-                CommonItemSeekBar("Status Bar Alpha", 255, mAlpha, object : SeekBar.OnSeekBarChangeListener {
+                CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+                    override fun getCurValue(): Int {
+                        return mAlpha
+                    }
+
                     override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                         mAlpha = progress
                         updateFakeStatusBar()
                     }
-
-                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                 })
         )
     }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt
index 639742c60b..435a1ecbed 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt
@@ -48,32 +48,28 @@ class BrightnessActivity : CommonActivity() {
 
     override fun bindItems(): MutableList> {
         return CollectionUtils.newArrayList(
-                CommonItemSeekBar("getBrightness", 255, BrightnessUtils.getBrightness(), object : SeekBar.OnSeekBarChangeListener {
+                CommonItemSeekBar("getBrightness", 255, object : CommonItemSeekBar.ProgressListener() {
+                    override fun getCurValue(): Int {
+                        return BrightnessUtils.getBrightness()
+                    }
+
                     override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                         BrightnessUtils.setBrightness(progress)
                     }
-
-                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                 }),
-                CommonItemSeekBar("getWindowBrightness", 255, BrightnessUtils.getWindowBrightness(window), object : SeekBar.OnSeekBarChangeListener {
+                CommonItemSeekBar("getWindowBrightness", 255, object : CommonItemSeekBar.ProgressListener() {
+                    override fun getCurValue(): Int {
+                        return BrightnessUtils.getWindowBrightness(window)
+                    }
+
                     override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                         BrightnessUtils.setWindowBrightness(window, progress)
                     }
-
-                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
-                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                 }),
                 CommonItemSwitch(
                         R.string.brightness_auto_brightness,
-                        Utils.Supplier {
-                            BrightnessUtils.isAutoBrightnessEnabled()
-                        },
-                        Utils.Consumer {
-                            BrightnessUtils.setAutoBrightnessEnabled(it)
-                        }
+                        { BrightnessUtils.isAutoBrightnessEnabled() },
+                        { BrightnessUtils.setAutoBrightnessEnabled(it) }
                 )
         )
     }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt
new file mode 100644
index 0000000000..824fdf02ca
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt
@@ -0,0 +1,76 @@
+package com.blankj.utilcode.pkg.feature.clipboard
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.ClipboardUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog  : http://blankj.com
+ * time  : 2020/09/11
+ * desc  : demo about ClipboardUtils
+ * ```
+ */
+class ClipboardActivity : CommonActivity() {
+
+    private var index: Int = 0
+    private var isAddListener: Boolean = false
+    private var listener = {
+        ToastUtils.showShort(ClipboardUtils.getText())
+    }
+
+    companion object {
+        fun start(context: Context) {
+            val starter = Intent(context, ClipboardActivity::class.java)
+            context.startActivity(starter)
+        }
+    }
+
+    override fun bindTitleRes(): Int {
+        return R.string.demo_clipboard
+    }
+
+    override fun bindItems(): MutableList> {
+        return CollectionUtils.newArrayList(
+                CommonItemTitle("getText", ClipboardUtils.getText()),
+                CommonItemTitle("getLabel", ClipboardUtils.getLabel()),
+                CommonItemClick("copyText: value{$index}").setOnItemClickListener { _, _, _ ->
+                    ClipboardUtils.copyText("value{${index++}}")
+                    itemsView.updateItems(bindItems())
+                },
+                CommonItemClick("clear").setOnItemClickListener { _, _, _ ->
+                    ClipboardUtils.clear()
+                    itemsView.updateItems(bindItems())
+                },
+                CommonItemSwitch("clipChangeListener", { isAddListener }, {
+                    isAddListener = it
+                    if (isAddListener) {
+                        ClipboardUtils.addChangedListener(listener)
+                    } else {
+                        ClipboardUtils.removeChangedListener(listener)
+                    }
+                })
+        )
+    }
+
+    override fun onResume() {
+        super.onResume()
+        itemsView.updateItems(bindItems())
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        if (isAddListener) {
+            ClipboardUtils.removeChangedListener(listener)
+        }
+    }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt
index dbfa38083c..c5f602b9e3 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt
@@ -50,12 +50,8 @@ class FlashlightActivity : CommonActivity() {
             if (FlashlightUtils.isFlashlightEnable()) {
                 add(CommonItemSwitch(
                         R.string.flashlight_status,
-                        Utils.Supplier {
-                            FlashlightUtils.isFlashlightOn()
-                        },
-                        Utils.Consumer {
-                            FlashlightUtils.setFlashlightStatus(it)
-                        }
+                        { FlashlightUtils.isFlashlightOn() },
+                        { FlashlightUtils.setFlashlightStatus(it) }
                 ))
             }
         }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
index 5035274ad9..995bbb22c1 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
@@ -119,71 +119,77 @@ class ImageActivity : CommonActivity() {
                     }
                 })
             })
-            add(CommonItemImage(R.string.image_src, Utils.Consumer {
+            add(CommonItemImage(R.string.image_src) {
                 it.setImageBitmap(src)
-            }))
-            add(CommonItemImage(R.string.image_add_color, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_add_color) {
                 it.setImageBitmap(ImageUtils.drawColor(src, Color.parseColor("#8000FF00")))
-            }))
-            add(CommonItemImage(R.string.image_scale, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_scale) {
                 it.setImageBitmap(ImageUtils.scale(src, width / 2, height / 2))
-            }))
-            add(CommonItemImage(R.string.image_clip, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_clip) {
                 it.setImageBitmap(ImageUtils.clip(src, 0, 0, width / 2, height / 2))
-            }))
-            add(CommonItemImage(R.string.image_skew, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_skew) {
                 it.setImageBitmap(ImageUtils.skew(src, 0.2f, 0.1f))
-            }))
-            add(CommonItemImage(R.string.image_rotate, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_rotate) {
                 it.setImageBitmap(ImageUtils.rotate(src, 90, (width / 2).toFloat(), (height / 2).toFloat()))
-            }))
-            add(CommonItemImage(R.string.image_to_round) { it ->
+            })
+            add(CommonItemImage(R.string.image_to_round) {
                 it.setImageBitmap(ImageUtils.toRound(src))
             })
-            add(CommonItemImage(R.string.image_to_round_border, Utils.Consumer {
+            add(CommonItemImage(R.string.image_to_round_border) {
                 it.setImageBitmap(ImageUtils.toRound(src, 16, Color.GREEN))
-            }))
-            add(CommonItemImage(R.string.image_to_round_corner, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_to_round_corner) {
                 it.setImageBitmap(ImageUtils.toRoundCorner(src, 80f))
-            }))
-            add(CommonItemImage(R.string.image_to_round_corner_border, Utils.Consumer {
-                it.setImageBitmap(ImageUtils.toRoundCorner(src, 80f, 16, Color.GREEN))
-            }))
-            add(CommonItemImage(R.string.image_add_corner_border, Utils.Consumer {
-                it.setImageBitmap(ImageUtils.addCornerBorder(src, 16, Color.GREEN, 0f))
-            }))
-            add(CommonItemImage(R.string.image_add_circle_border, Utils.Consumer {
-                it.setImageBitmap(ImageUtils.addCircleBorder(round, 16, Color.GREEN))
-            }))
-            add(CommonItemImage(R.string.image_add_reflection, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_to_round_corner_border) {
+                it.setImageBitmap(ImageUtils.toRoundCorner(src, 80f, 16f, Color.GREEN))
+            })
+            add(CommonItemImage(R.string.image_to_round_corner_border) {
+                it.setImageBitmap(ImageUtils.toRoundCorner(src, floatArrayOf(0f, 0f, 80f, 80f, 0f, 0f, 80f, 80f), 16f, Color.GREEN))
+            })
+            add(CommonItemImage(R.string.image_add_corner_border) {
+                it.setImageBitmap(ImageUtils.addCornerBorder(src, 16f, Color.GREEN, 80f))
+            })
+            add(CommonItemImage(R.string.image_add_corner_border) {
+                it.setImageBitmap(ImageUtils.addCornerBorder(src, 16f, Color.GREEN, floatArrayOf(0f, 0f, 80f, 80f, 0f, 0f, 80f, 80f)))
+            })
+            add(CommonItemImage(R.string.image_add_circle_border) {
+                it.setImageBitmap(ImageUtils.addCircleBorder(src, 16f, Color.GREEN))
+            })
+            add(CommonItemImage(R.string.image_add_reflection) {
                 it.setImageBitmap(ImageUtils.addReflection(src, 80))
-            }))
-            add(CommonItemImage(R.string.image_add_text_watermark, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_add_text_watermark) {
                 it.setImageBitmap(ImageUtils.addTextWatermark(src, "blankj", 40, Color.GREEN, 0f, 0f))
-            }))
-            add(CommonItemImage(R.string.image_add_image_watermark, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_add_image_watermark) {
                 it.setImageBitmap(ImageUtils.addImageWatermark(src, watermark, 0, 0, 0x88))
-            }))
-            add(CommonItemImage(R.string.image_to_gray, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_to_gray) {
                 it.setImageBitmap(ImageUtils.toGray(src))
-            }))
-            add(CommonItemImage(R.string.image_fast_blur, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_fast_blur) {
                 it.setImageBitmap(ImageUtils.fastBlur(src, 0.1f, 5f))
-            }))
+            })
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-                add(CommonItemImage(R.string.image_render_script_blur, Utils.Consumer {
+                add(CommonItemImage(R.string.image_render_script_blur) {
                     it.setImageBitmap(ImageUtils.renderScriptBlur(src, 10f))
-                }))
+                })
             }
-            add(CommonItemImage(R.string.image_stack_blur, Utils.Consumer {
+            add(CommonItemImage(R.string.image_stack_blur) {
                 it.setImageBitmap(ImageUtils.stackBlur(src, 10))
-            }))
-            add(CommonItemImage(R.string.image_compress_by_scale, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_compress_by_scale) {
                 it.setImageBitmap(ImageUtils.compressByScale(src, 0.5f, 0.5f))
-            }))
-            add(CommonItemImage(R.string.image_compress_by_sample_size, Utils.Consumer {
+            })
+            add(CommonItemImage(R.string.image_compress_by_sample_size) {
                 it.setImageBitmap(ImageUtils.compressBySampleSize(src, 2))
-            }))
+            })
         }
     }
 
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt
index 5d088ba01c..0e14482b91 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt
@@ -3,15 +3,15 @@ package com.blankj.utilcode.pkg.feature.language
 import android.content.Context
 import android.content.Intent
 import com.blankj.common.activity.CommonActivity
-import com.blankj.common.activity.CommonActivityItemsView
-import com.blankj.common.activity.CommonActivityTitleView
 import com.blankj.common.item.CommonItem
 import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
 import com.blankj.utilcode.pkg.R
-import com.blankj.utilcode.pkg.feature.CoreUtilActivity
 import com.blankj.utilcode.util.CollectionUtils
 import com.blankj.utilcode.util.LanguageUtils
-import com.blankj.utilcode.util.ToastUtils
+import com.blankj.utilcode.util.SPStaticUtils
+import com.blankj.utilcode.util.StringUtils
 import java.util.*
 
 /**
@@ -25,6 +25,9 @@ import java.util.*
 class LanguageActivity : CommonActivity() {
 
     companion object {
+
+        const val SP_KEY_IS_RELAUNCH_APP = "SP_KEY_IS_RELAUNCH_APP"
+
         fun start(context: Context) {
             val starter = Intent(context, LanguageActivity::class.java)
             context.startActivity(starter)
@@ -37,21 +40,31 @@ class LanguageActivity : CommonActivity() {
 
     override fun bindItems(): List> {
         return CollectionUtils.newArrayList(
-                CommonItemClick(R.string.language_app_context) {
-                    ToastUtils.showLong(R.string.language)
-                },
-                CommonItemClick(R.string.language_activity_context) {
-                    ToastUtils.showLong(getString(R.string.language))
-                },
+                CommonItemTitle("isAppliedLanguage", LanguageUtils.isAppliedLanguage().toString()),
+                CommonItemTitle("isAppliedLanguage(SIMPLIFIED_CHINESE)", LanguageUtils.isAppliedLanguage(Locale.SIMPLIFIED_CHINESE).toString()),
+                CommonItemTitle("getAppliedLanguage", (LanguageUtils.getAppliedLanguage() ?: "null").toString()),
+                CommonItemTitle("getActivityContextLanguage", LanguageUtils.getContextLanguage(this).toString()),
+                CommonItemTitle("getAppContextLanguage", LanguageUtils.getAppContextLanguage().toString()),
+                CommonItemTitle("getSystemLanguage", LanguageUtils.getSystemLanguage().toString()),
+                CommonItemSwitch(
+                        StringUtils.getString(R.string.language_relaunch_app),
+                        { isRelaunchApp() },
+                        { SPStaticUtils.put(SP_KEY_IS_RELAUNCH_APP, it) }
+                ),
                 CommonItemClick(R.string.language_apply_simple_chinese) {
-                    LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, CoreUtilActivity::class.java)
+                    LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, isRelaunchApp())
                 },
                 CommonItemClick(R.string.language_apply_american) {
-                    LanguageUtils.applyLanguage(Locale.US, "")
+                    LanguageUtils.applyLanguage(Locale.US, isRelaunchApp())
+                },
+                CommonItemClick(R.string.language_apply_english) {
+                    LanguageUtils.applyLanguage(Locale.ENGLISH, isRelaunchApp())
                 },
                 CommonItemClick(R.string.language_apply_system) {
-                    LanguageUtils.applySystemLanguage("")
+                    LanguageUtils.applySystemLanguage(isRelaunchApp())
                 }
         )
     }
+
+    private fun isRelaunchApp() = SPStaticUtils.getBoolean(SP_KEY_IS_RELAUNCH_APP)
 }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt
index b26bd9644c..096df003e4 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt
@@ -5,11 +5,13 @@ import android.content.Context
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
+import android.util.Log
 import com.blankj.base.BaseApplication
 import com.blankj.common.activity.CommonActivity
 import com.blankj.common.item.CommonItem
 import com.blankj.common.item.CommonItemClick
 import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
 import com.blankj.utilcode.pkg.R
 import com.blankj.utilcode.util.*
 import java.io.File
@@ -112,23 +114,21 @@ class LogActivity : CommonActivity() {
 
     override fun bindItems(): List> {
         return CollectionUtils.newArrayList(
+                CommonItemTitle("getLogFiles", LogUtils.getLogFiles().toString()),
                 CommonItemSwitch(
                         R.string.log_switch,
-                        Utils.Supplier {
-                            mConfig.isLogSwitch
-                        },
-                        Utils.Consumer {
-                            mConfig.isLogSwitch = it
-                        }
+                        { mConfig.isLogSwitch },
+                        { mConfig.isLogSwitch = it }
                 ),
                 CommonItemSwitch(
-                        R.string.log_console_console,
-                        Utils.Supplier {
-                            mConfig.isLog2ConsoleSwitch
-                        },
-                        Utils.Consumer {
-                            mConfig.setConsoleSwitch(it)
-                        }
+                        R.string.log_console_switch,
+                        { mConfig.isLog2ConsoleSwitch },
+                        { mConfig.setConsoleSwitch(it) }
+                ),
+                CommonItemSwitch(
+                        R.string.log_console_listener_switch,
+                        { mConfig.haveSetOnConsoleOutputListener() },
+                        { mConfig.setOnConsoleOutputListener { type, tag, content -> Log.println(type, tag, content) } }
                 ),
                 CommonItemClick("Global Tag", if (mConfig.globalTag == "") "null" else mConfig.globalTag).setOnClickUpdateContentListener {
                     if (StringUtils.isSpace(mConfig.globalTag)) {
@@ -140,47 +140,41 @@ class LogActivity : CommonActivity() {
                 },
                 CommonItemSwitch(
                         R.string.log_head_switch,
-                        Utils.Supplier {
-                            mConfig.isLogHeadSwitch
-                        },
-                        Utils.Consumer {
-                            mConfig.isLogHeadSwitch = it
-                        }
+                        { mConfig.isLogHeadSwitch },
+                        { mConfig.isLogHeadSwitch = it }
                 ),
                 CommonItemSwitch(
                         R.string.log_file_switch,
-                        Utils.Supplier {
-                            mConfig.isLog2FileSwitch
-                        },
-                        Utils.Consumer {
-                            mConfig.isLog2FileSwitch = it
-                        }
+                        { mConfig.isLog2FileSwitch },
+                        { mConfig.isLog2FileSwitch = it }
+                ),
+                CommonItemSwitch(
+                        R.string.log_file_listener_switch,
+                        { mConfig.haveSetOnFileOutputListener() },
+                        { mConfig.setOnFileOutputListener { filePath, content -> Log.d("LogActivity", filePath + "\n" + content) } }
                 ),
                 CommonItemClick("Dir", mConfig.dir).setOnClickUpdateContentListener {
                     if (mConfig.dir != mConfig.defaultDir) {
                         mConfig.dir = mConfig.defaultDir
                     } else {
-                        mConfig.setDir(File(PathUtils.getInternalAppFilesPath(), "log"))
+                        mConfig.setDir(File(PathUtils.getExternalAppFilesPath(), "log"))
                     }
                     return@setOnClickUpdateContentListener mConfig.dir
                 },
                 CommonItemSwitch(
                         R.string.log_border_switch,
-                        Utils.Supplier {
-                            mConfig.isLogBorderSwitch
-                        },
-                        Utils.Consumer {
-                            mConfig.setBorderSwitch(it)
-                        }
+                        { mConfig.isLogBorderSwitch },
+                        { mConfig.setBorderSwitch(it) }
+                ),
+                CommonItemSwitch(
+                        R.string.log_single_tag_switch,
+                        { mConfig.isSingleTagSwitch },
+                        { mConfig.setSingleTagSwitch(it) }
                 ),
                 CommonItemSwitch(
                         R.string.log_single_tag_switch,
-                        Utils.Supplier {
-                            mConfig.isSingleTagSwitch
-                        },
-                        Utils.Consumer {
-                            mConfig.setSingleTagSwitch(it)
-                        }
+                        { mConfig.isSingleTagSwitch },
+                        { mConfig.setSingleTagSwitch(it) }
                 ),
                 CommonItemClick("ConsoleFilter", mConfig.consoleFilter.toString()).setOnClickUpdateContentListener {
                     mConfig.setConsoleFilter(if (mConfig.consoleFilter == 'V') LogUtils.W else LogUtils.V)
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt
index f45304d353..77bb5f8e82 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt
@@ -3,8 +3,6 @@ package com.blankj.utilcode.pkg.feature.metaData
 import android.content.Context
 import android.content.Intent
 import com.blankj.common.activity.CommonActivity
-import com.blankj.common.activity.CommonActivityItemsView
-import com.blankj.common.activity.CommonActivityTitleView
 import com.blankj.common.item.CommonItem
 import com.blankj.common.item.CommonItemTitle
 import com.blankj.utilcode.pkg.R
@@ -35,7 +33,7 @@ class MetaDataActivity : CommonActivity() {
     override fun bindItems(): List> {
         return CollectionUtils.newArrayList(
                 CommonItemTitle("getMetaDataInApp", MetaDataUtils.getMetaDataInApp("app_meta_data")),
-                CommonItemTitle("getMetaDataInActivity", MetaDataUtils.getMetaDataInActivity(this, "activity_meta_data"))
+                CommonItemTitle("getMetaDataInActivity", MetaDataUtils.getMetaDataInActivity(this, "activity_meta_data").substring(1))
         )
     }
 }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java
index 59ab715ac0..054cd7ade9 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java
@@ -1,12 +1,16 @@
 package com.blankj.utilcode.pkg.feature.mvp;
 
-import android.support.v4.app.FragmentActivity;
+import android.text.Layout;
 import android.view.View;
 import android.widget.TextView;
 
 import com.blankj.base.mvp.BaseView;
 import com.blankj.utilcode.pkg.R;
+import com.blankj.utilcode.pkg.feature.fragment.FragmentActivity;
 import com.blankj.utilcode.util.ClickUtils;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SizeUtils;
+import com.blankj.utilcode.util.ThreadUtils;
 import com.blankj.utilcode.util.ToastUtils;
 
 /**
@@ -21,8 +25,10 @@ public class MvpView extends BaseView
         implements IMvp.View {
 
     private TextView mvpTv;
+    private TextView mvpMeasureWidthTv;
+    private int      i = 0;
 
-    public MvpView(FragmentActivity activity) {
+    public MvpView(MvpActivity activity) {
         super(activity);
         mvpTv = activity.findViewById(R.id.mvpUpdateTv);
         ClickUtils.applyPressedBgDark(mvpTv);
@@ -32,6 +38,23 @@ public void onClick(View v) {
                 getPresenter(MvpPresenter.class).updateMsg();
             }
         });
+
+        mvpMeasureWidthTv = activity.findViewById(R.id.mvpMeasureWidthTv);
+
+        measure();
+    }
+
+    private void measure() {
+        ThreadUtils.runOnUiThreadDelayed(new Runnable() {
+            @Override
+            public void run() {
+                float textWidth = Layout.getDesiredWidth(mvpMeasureWidthTv.getText(), mvpMeasureWidthTv.getPaint()) + SizeUtils.dp2px(16);
+                float textWidth2 = mvpMeasureWidthTv.getPaint().measureText(mvpMeasureWidthTv.getText().toString()) + SizeUtils.dp2px(16);
+                LogUtils.i(mvpMeasureWidthTv.getWidth(), textWidth, textWidth2);
+                mvpMeasureWidthTv.setText(mvpMeasureWidthTv.getText().toString() + i);
+                measure();
+            }
+        }, 1000);
     }
 
     @Override
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt
index 2d39faf102..f0c9962b2d 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt
@@ -75,10 +75,8 @@ class NetworkActivity : CommonActivity(), NetworkUtils.OnNetworkStatusChangedLis
 
                 CommonItemSwitch(
                         R.string.network_wifi_enabled,
-                        Utils.Supplier {
-                            NetworkUtils.getWifiEnabled()
-                        },
-                        Utils.Consumer {
+                        { NetworkUtils.getWifiEnabled() },
+                        {
                             NetworkUtils.setWifiEnabled(it)
                             ThreadUtils.executeByIo(getItemsTask())
                         }
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt
index 6f69405355..c55d9c945b 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt
@@ -1,6 +1,6 @@
 package com.blankj.utilcode.pkg.feature.permission
 
-import android.Manifest
+import android.Manifest.permission
 import android.content.Context
 import android.content.Intent
 import android.os.Build
@@ -56,56 +56,36 @@ class PermissionActivity : CommonActivity() {
             add(CommonItemClick(R.string.permission_open_app_settings, true) { PermissionUtils.launchAppDetailsSettings() })
             add(CommonItemSwitch(
                     R.string.permission_calendar_status,
-                    Utils.Supplier {
-                        return@Supplier PermissionUtils.isGranted(Manifest.permission.READ_CALENDAR)
-                    },
-                    Utils.Consumer {
-                        requestCalendar()
-                    }
+                    { PermissionUtils.isGranted(PermissionConstants.CALENDAR) },
+                    { requestCalendar() }
             ))
             add(CommonItemSwitch(
                     R.string.permission_record_audio_status,
-                    Utils.Supplier {
-                        return@Supplier PermissionUtils.isGranted(Manifest.permission.RECORD_AUDIO)
-                    },
-                    Utils.Consumer {
-                        requestRecordAudio()
-                    }
+                    { PermissionUtils.isGranted(PermissionConstants.MICROPHONE) },
+                    { requestRecordAudio() }
             ))
             add(CommonItemSwitch(
                     R.string.permission_calendar_and_record_audio_status,
-                    Utils.Supplier {
-                        return@Supplier PermissionUtils.isGranted(Manifest.permission.READ_CALENDAR, Manifest.permission.RECORD_AUDIO)
-                    },
-                    Utils.Consumer {
-                        requestCalendarAndRecordAudio()
-                    }
+                    { PermissionUtils.isGranted(PermissionConstants.CALENDAR, PermissionConstants.MICROPHONE) },
+                    { requestCalendarAndRecordAudio() }
             ))
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 add(CommonItemSwitch(
                         R.string.permission_write_settings_status,
-                        Utils.Supplier {
-                            return@Supplier PermissionUtils.isGrantedWriteSettings()
-                        },
-                        Utils.Consumer {
-                            requestWriteSettings()
-                        }
+                        { PermissionUtils.isGrantedWriteSettings() },
+                        { requestWriteSettings() }
                 ))
                 add(CommonItemSwitch(
                         R.string.permission_write_settings_status,
-                        Utils.Supplier {
-                            return@Supplier PermissionUtils.isGrantedDrawOverlays()
-                        },
-                        Utils.Consumer {
-                            requestDrawOverlays()
-                        }
+                        { PermissionUtils.isGrantedDrawOverlays() },
+                        { requestDrawOverlays() }
                 ))
             }
         }
     }
 
     private fun requestCalendar() {
-        PermissionUtils.permission(PermissionConstants.CALENDAR)
+        PermissionUtils.permissionGroup(PermissionConstants.CALENDAR)
                 .rationale { activity, shouldRequest -> PermissionHelper.showRationaleDialog(activity, shouldRequest) }
                 .callback(object : PermissionUtils.FullCallback {
                     override fun onGranted(permissionsGranted: List) {
@@ -130,7 +110,7 @@ class PermissionActivity : CommonActivity() {
     }
 
     private fun requestRecordAudio() {
-        PermissionUtils.permission(PermissionConstants.MICROPHONE)
+        PermissionUtils.permissionGroup(PermissionConstants.MICROPHONE)
                 .rationale { activity, shouldRequest -> PermissionHelper.showRationaleDialog(activity, shouldRequest) }
                 .callback(object : PermissionUtils.FullCallback {
                     override fun onGranted(permissionsGranted: List) {
@@ -154,28 +134,21 @@ class PermissionActivity : CommonActivity() {
     }
 
     private fun requestCalendarAndRecordAudio() {
-        PermissionUtils.permission(PermissionConstants.CALENDAR, PermissionConstants.MICROPHONE)
-                .rationale { activity, shouldRequest -> PermissionHelper.showRationaleDialog(activity, shouldRequest) }
-                .callback(object : PermissionUtils.FullCallback {
-                    override fun onGranted(permissionsGranted: List) {
-                        LogUtils.d(permissionsGranted)
-                        if (permissionsGranted.size == 2) {
-                            showSnackbar(true, "Calendar or Microphone is granted")
-                        }
-                        itemsView.updateItems(bindItems())
+        PermissionUtils.permission(permission.READ_CALENDAR, permission.RECORD_AUDIO)
+                .explain { activity, denied, shouldRequest -> PermissionHelper.showExplainDialog(activity, denied, shouldRequest) }
+                .callback { isAllGranted, granted, deniedForever, denied ->
+                    LogUtils.d(granted, deniedForever, denied)
+                    itemsView.updateItems(bindItems())
+                    if (isAllGranted) {
+                        showSnackbar(true, "Calendar and Microphone are granted")
+                        return@callback
                     }
-
-                    override fun onDenied(permissionsDeniedForever: List,
-                                          permissionsDenied: List) {
-                        LogUtils.d(permissionsDeniedForever, permissionsDenied)
-                        if (permissionsDeniedForever.isNotEmpty()) {
-                            showSnackbar(false, "Calendar or Microphone is denied forever")
-                        } else {
-                            showSnackbar(false, "Calendar or Microphone is denied")
-                        }
-                        itemsView.updateItems(bindItems())
+                    if (deniedForever.isNotEmpty()) {
+                        showSnackbar(false, "Calendar or Microphone is denied forever")
+                    } else {
+                        showSnackbar(false, "Calendar or Microphone is denied")
                     }
-                })
+                }
                 .request()
     }
 
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/toast/CustomToast.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
index 314ba33d59..384b1877ea 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 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..5d55e3c754 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,7 +3,6 @@ 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 com.blankj.common.activity.CommonActivity
 import com.blankj.common.item.CommonItem
@@ -11,6 +10,7 @@ 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 +38,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 +58,40 @@ 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_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/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/res/layout/mvp_activity.xml b/feature/utilcode/pkg/src/main/res/layout/mvp_activity.xml
index 807c158b67..d594eb654d 100644
--- a/feature/utilcode/pkg/src/main/res/layout/mvp_activity.xml
+++ b/feature/utilcode/pkg/src/main/res/layout/mvp_activity.xml
@@ -14,4 +14,17 @@
         android:text="Get Update Msg"
         app:layout_constraintTop_toTopOf="parent" />
 
+    
+
 
\ 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..414fa48424 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,9 @@
 
     Language Demo
 
-    Language
-    Language App Context
-    Language Activity Context
     Apply Simple Chinese
     Apply American
+    Apply English
     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..5cab96988f 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,9 @@
 
     语言例子
 
-    语言
-    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 5bea803e40..ed7e15412f 100644
--- a/feature/utilcode/pkg/src/main/res/values/strings.xml
+++ b/feature/utilcode/pkg/src/main/res/values/strings.xml
@@ -9,6 +9,7 @@
     BusUtils Demo
     CleanUtils Demo
     ClickUtils Demo
+    ClipboardUtils Demo
     CrashUtils Demo
     DeviceUtils Demo
     FileUtils Demo
@@ -41,6 +42,7 @@
     UiMessage Demo
     TransActivity Demo
     VibrateUtils Demo
+    VolumeUtils Demo
 
     
     Shared Element
@@ -227,18 +229,19 @@
     Close Dialog
 
     
-    Language
-    Language App Context
-    Language Activity Context
+    Relaunch App
     Apply Simple Chinese
     Apply American
+    Apply English
     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
@@ -325,15 +328,22 @@
     
     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
     Cancel
     Show Toast Dialog
+    Show Toast When Start Activity
     Short
     Long
     Green Font
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..da049b589c 100644
--- a/lib/base/src/main/java/com/blankj/base/BaseApplication.java
+++ b/lib/base/src/main/java/com/blankj/base/BaseApplication.java
@@ -74,15 +74,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/mvp/BasePresenter.java b/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java
index a067e2aff5..2c6806708a 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
@@ -47,9 +47,9 @@ public  M getModel(Class modelClass) {
             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;
     }
diff --git a/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java b/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java
index e7e4c0475d..6a58dfea04 100644
--- a/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java
+++ b/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java
@@ -1,5 +1,6 @@
 package com.blankj.common.activity;
 
+import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.CallSuper;
 import android.support.annotation.NonNull;
@@ -20,6 +21,7 @@
 import com.blankj.common.dialog.CommonDialogLoading;
 import com.blankj.common.item.CommonItem;
 import com.blankj.swipepanel.SwipePanel;
+import com.blankj.utilcode.util.LanguageUtils;
 import com.blankj.utilcode.util.SizeUtils;
 
 import java.util.List;
@@ -42,6 +44,11 @@ public abstract class CommonActivity extends BaseActivity {
 
     public View commonContentView;
 
+//    @Override
+//    protected void attachBaseContext(Context newBase) {
+//        super.attachBaseContext(LanguageUtils.attachBaseContext(newBase));
+//    }
+
     ///////////////////////////////////////////////////////////////////////////
     // title view
     ///////////////////////////////////////////////////////////////////////////
diff --git a/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt b/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt
index 00ac76df68..1df23cb1a4 100644
--- a/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt
+++ b/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt
@@ -19,7 +19,7 @@ import com.blankj.utilcode.util.*
 object PermissionHelper {
 
     fun request(context: Context, callback: PermissionUtils.SimpleCallback,
-                @PermissionConstants.Permission vararg permissions: String) {
+                @PermissionConstants.PermissionGroup vararg permissions: String) {
         PermissionUtils.permission(*permissions)
                 .rationale { activity, shouldRequest -> showRationaleDialog(activity, shouldRequest) }
                 .callback(object : PermissionUtils.SingleCallback {
@@ -68,6 +68,20 @@ object PermissionHelper {
                 .show()
     }
 
+    fun showExplainDialog(context: Context, denied: List, shouldRequest: PermissionUtils.OnExplainListener.ShouldRequest) {
+        CommonDialogContent().init(context,
+                StringUtils.getString(android.R.string.dialog_alert_title),
+                "We needs the permissions of $denied to test the utils of permission.",
+                Pair(StringUtils.getString(android.R.string.ok), View.OnClickListener {
+                    shouldRequest.start(true)
+                }),
+                Pair(StringUtils.getString(android.R.string.cancel), View.OnClickListener {
+                    ToastUtils.showShort("request failed.")
+                    shouldRequest.start(false)
+                }))
+                .show()
+    }
+
     fun showOpenAppSettingDialog(context: Context) {
         CommonDialogContent().init(context,
                 StringUtils.getString(android.R.string.dialog_alert_title),
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java b/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
index 2629e3d2d5..c68db9dc9f 100644
--- a/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
@@ -21,22 +21,22 @@
  */
 public class CommonItemSeekBar extends CommonItem {
 
-    private CharSequence                    mTitle;
-    private CharSequence                    mContent;
-    private int                             mMaxProgress;
-    private int                             mCurProgress;
-    private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;
-
-    public CommonItemSeekBar(@StringRes int title, int maxProgress, int curProgress, @NonNull SeekBar.OnSeekBarChangeListener itemClickListener) {
-        this(StringUtils.getString(title), maxProgress, curProgress, itemClickListener);
+    private CharSequence     mTitle;
+    private CharSequence     mContent;
+    private int              mMaxProgress;
+    private int              mCurProgress;
+    private ProgressListener mProgressListener;
+
+    public CommonItemSeekBar(@StringRes int title, int maxProgress, @NonNull ProgressListener listener) {
+        this(StringUtils.getString(title), maxProgress, listener);
     }
 
-    public CommonItemSeekBar(@NonNull CharSequence title, int maxProgress, int curProgress, @NonNull SeekBar.OnSeekBarChangeListener itemClickListener) {
+    public CommonItemSeekBar(@NonNull CharSequence title, int maxProgress, @NonNull ProgressListener listener) {
         super(R.layout.common_item_title_seekbar);
         mTitle = title;
         mMaxProgress = maxProgress;
-        mCurProgress = curProgress;
-        mOnSeekBarChangeListener = itemClickListener;
+        mCurProgress = listener.getCurValue();
+        mProgressListener = listener;
         mContent = String.valueOf(mCurProgress);
     }
 
@@ -62,19 +62,21 @@ public boolean onTouch(View v, MotionEvent event) {
         seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
             @Override
             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
-                mCurProgress = progress;
-                contentTv.setText(String.valueOf(progress));
+                mProgressListener.onProgressChanged(seekBar, progress, fromUser);
+                int curValue = mProgressListener.getCurValue();
+                mCurProgress = curValue;
+                contentTv.setText(String.valueOf(curValue));
+                seekBar.setProgress(curValue);
             }
 
             @Override
             public void onStartTrackingTouch(SeekBar seekBar) {
-                mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
+                mProgressListener.onStartTrackingTouch(seekBar);
             }
 
             @Override
             public void onStopTrackingTouch(SeekBar seekBar) {
-                mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
+                mProgressListener.onStopTrackingTouch(seekBar);
             }
         });
     }
@@ -87,4 +89,17 @@ public void setTitle(CharSequence title) {
     public CharSequence getTitle() {
         return mTitle;
     }
+
+    public static abstract class ProgressListener implements SeekBar.OnSeekBarChangeListener {
+
+        public abstract int getCurValue();
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+        }
+    }
 }
diff --git a/lib/subutil/README-CN.md b/lib/subutil/README-CN.md
index 2a8b920cf8..a712609087 100644
--- a/lib/subutil/README-CN.md
+++ b/lib/subutil/README-CN.md
@@ -18,16 +18,6 @@ isRegisteredBatteryStatusChangedListener: 判断是否注册电池状态改变
 unregisterBatteryStatusChangedListener  : 注销电池状态改变监听器
 ```
 
-* ### 剪贴板相关 -> [ClipboardUtils.java][clipboard.java] -> [Test][clipboard.test]
-```
-copyText  : 复制文本到剪贴板
-getText   : 获取剪贴板的文本
-copyUri   : 复制 uri 到剪贴板
-getUri    : 获取剪贴板的 uri
-copyIntent: 复制意图到剪贴板
-getIntent : 获取剪贴板的意图
-```
-
 * ### 坐标转换相关 -> [CoordinateUtils.java][coordinate.java] -> [Test][coordinate.test]
 ```
 bd09ToGcj02 : BD09 坐标转 GCJ02 坐标
@@ -91,9 +81,6 @@ getSurnameFirstLetter: 根据名字获取姓氏的首字母
 [battery.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java
 [battery.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/battery/BatteryActivity.kt
 
-[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
-[clipboard.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
-
 [coordinate.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
 [coordinate.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/CoordinateUtilsTest.java
 
diff --git a/lib/subutil/README.md b/lib/subutil/README.md
index 0ebcf92e8b..f25b631c1b 100644
--- a/lib/subutil/README.md
+++ b/lib/subutil/README.md
@@ -18,16 +18,6 @@ isRegisteredBatteryStatusChangedListener
 unregisterBatteryStatusChangedListener
 ```
 
-* ### About Clipboard -> [ClipboardUtils.java][clipboard.java] -> [Test][clipboard.test]
-```
-copyText
-getText
-copyUri
-getUri
-copyIntent
-getIntent
-```
-
 * ### About Coordinate -> [CoordinateUtils.java][coordinate.java] -> [Test][coordinate.test]
 ```
 bd09ToGcj02
@@ -91,9 +81,6 @@ getSurnameFirstLetter
 [battery.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java
 [battery.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/battery/BatteryActivity.kt
 
-[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
-[clipboard.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
-
 [coordinate.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
 [coordinate.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/CoordinateUtilsTest.java
 
diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/AppStoreUtils.java b/lib/subutil/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
index 61b497a462..92aa89be0b 100644
--- a/lib/subutil/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
+++ b/lib/subutil/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
@@ -1,13 +1,12 @@
 package com.blankj.subutil.util;
 
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
-import android.text.TextUtils;
 import android.util.Log;
 
+import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.RomUtils;
 import com.blankj.utilcode.util.Utils;
 
@@ -88,7 +87,7 @@ public static Intent getAppStoreIntent(final String packageName, boolean isInclu
         for (ResolveInfo resolveInfo : resolveInfos) {
             String pkgName = resolveInfo.activityInfo.packageName;
             if (!GOOGLE_PLAY_APP_STORE_PACKAGE_NAME.equals(pkgName)) {
-                if (isAppSystem(pkgName)) {
+                if (AppUtils.isAppSystem(pkgName)) {
                     intent.setPackage(pkgName);
                     return intent;
                 }
@@ -105,25 +104,6 @@ public static Intent getAppStoreIntent(final String packageName, boolean isInclu
         return intent;
     }
 
-    private static boolean go2NormalAppStore(String packageName) {
-        Intent intent = getNormalAppStoreIntent();
-        if (intent == null) return false;
-        intent.setData(Uri.parse("market://details?id=" + packageName));
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        Utils.getApp().startActivity(intent);
-        return true;
-    }
-
-    private static Intent getNormalAppStoreIntent() {
-        Intent intent = new Intent();
-        Uri uri = Uri.parse("market://details?id=" + Utils.getApp().getPackageName());
-        intent.setData(uri);
-        if (getAvailableIntentSize(intent) > 0) {
-            return intent;
-        }
-        return null;
-    }
-
     private static Intent getSamsungAppStoreIntent(final String packageName) {
         Intent intent = new Intent();
         intent.setClassName("com.sec.android.app.samsungapps", "com.sec.android.app.samsungapps.Main");
@@ -152,16 +132,4 @@ private static int getAvailableIntentSize(final Intent intent) {
                 .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
                 .size();
     }
-
-    private static boolean isAppSystem(final String packageName) {
-        if (TextUtils.isEmpty(packageName)) return false;
-        try {
-            PackageManager pm = Utils.getApp().getPackageManager();
-            ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
-            return ai != null && (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-        } catch (PackageManager.NameNotFoundException e) {
-            e.printStackTrace();
-            return false;
-        }
-    }
 }
diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java b/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
deleted file mode 100644
index 13f1061d7e..0000000000
--- a/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.blankj.subutil.util;
-
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-
-import com.blankj.utilcode.util.Utils;
-
-/**
- * 
- *     author: Blankj
- *     blog  : http://blankj.com
- *     time  : 2016/09/25
- *     desc  : 剪贴板相关工具类
- * 
- */ -public final class ClipboardUtils { - - private ClipboardUtils() { - throw new UnsupportedOperationException("u can't instantiate me..."); - } - - /** - * 复制文本到剪贴板 - * - * @param text 文本 - */ - public static void copyText(final CharSequence text) { - ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); - cm.setPrimaryClip(ClipData.newPlainText("text", text)); - } - - /** - * 获取剪贴板的文本 - * - * @return 剪贴板的文本 - */ - public static CharSequence getText() { - ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = cm.getPrimaryClip(); - if (clip != null && clip.getItemCount() > 0) { - return clip.getItemAt(0).coerceToText(Utils.getApp()); - } - return null; - } - - /** - * 复制uri到剪贴板 - * - * @param uri uri - */ - public static void copyUri(final Uri uri) { - ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); - cm.setPrimaryClip(ClipData.newUri(Utils.getApp().getContentResolver(), "uri", uri)); - } - - /** - * 获取剪贴板的uri - * - * @return 剪贴板的uri - */ - public static Uri getUri() { - ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = cm.getPrimaryClip(); - if (clip != null && clip.getItemCount() > 0) { - return clip.getItemAt(0).getUri(); - } - return null; - } - - /** - * 复制意图到剪贴板 - * - * @param intent 意图 - */ - public static void copyIntent(final Intent intent) { - ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); - cm.setPrimaryClip(ClipData.newIntent("intent", intent)); - } - - /** - * 获取剪贴板的意图 - * - * @return 剪贴板的意图 - */ - public static Intent getIntent() { - ClipboardManager cm = (ClipboardManager) Utils.getApp().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = cm.getPrimaryClip(); - if (clip != null && clip.getItemCount() > 0) { - return clip.getItemAt(0).getIntent(); - } - return null; - } -} diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/DangerousUtils.java b/lib/subutil/src/main/java/com/blankj/subutil/util/DangerousUtils.java index 8469d47a14..a2670674b4 100644 --- a/lib/subutil/src/main/java/com/blankj/subutil/util/DangerousUtils.java +++ b/lib/subutil/src/main/java/com/blankj/subutil/util/DangerousUtils.java @@ -325,7 +325,7 @@ public static boolean setMobileDataEnabled(final boolean enabled) { setDataEnabledMethod.invoke(tm, enabled); return true; } catch (Exception e) { - Log.e("NetworkUtils", "setMobileDataEnabled: ", e); + e.printStackTrace(); } return false; } diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/HttpsUtil.java b/lib/subutil/src/main/java/com/blankj/subutil/util/HttpsUtil.java index 24356f5187..e0acb09850 100644 --- a/lib/subutil/src/main/java/com/blankj/subutil/util/HttpsUtil.java +++ b/lib/subutil/src/main/java/com/blankj/subutil/util/HttpsUtil.java @@ -8,7 +8,11 @@ import java.util.Scanner; /** - * Create by MilkZS on 2019/1/9 13:36 + *
+ *     author: MilkZS
+ *     time  : 2019/01/09
+ *     desc  : https 工具类
+ * 
*/ public final class HttpsUtil { diff --git a/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java b/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java deleted file mode 100644 index e1d550fb5c..0000000000 --- a/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.blankj.subutil.util; - -import android.content.Intent; -import android.net.Uri; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.junit.Assert.assertEquals; - - -/** - *
- *     author: Blankj
- *     blog  : http://blankj.com
- *     time  : 2016/09/26
- *     desc  : ClipboardUtils 单元测试
- * 
- */ -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ClipboardUtilsTest { - - static { - TestUtils.init(); - } - - @Test - public void testText() throws Exception { - ClipboardUtils.copyText("test"); - assertEquals("test", ClipboardUtils.getText()); - } - - @Test - public void testUri() throws Exception { - ClipboardUtils.copyUri(Uri.parse("http://www.blankj.com/")); - System.out.println((ClipboardUtils.getUri())); - } - - @Test - public void testIntent() throws Exception { - Intent intent = new Intent(); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setAction(Intent.ACTION_DIAL); - ClipboardUtils.copyIntent(intent); - System.out.println(ClipboardUtils.getText()); - } -} \ No newline at end of file diff --git a/lib/subutil/src/test/java/com/blankj/subutil/util/TestUtils.java b/lib/subutil/src/test/java/com/blankj/subutil/util/TestUtils.java deleted file mode 100644 index 78422556ed..0000000000 --- a/lib/subutil/src/test/java/com/blankj/subutil/util/TestUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.blankj.subutil.util; - -import com.blankj.utilcode.util.Utils; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** - *
- *     author: Blankj
- *     blog  : http://blankj.com
- *     time  : 2016/08/21
- *     desc  : utils about test
- * 
- */ -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TestUtils { - - public static void init() { - Utils.init(RuntimeEnvironment.application); - } - - @Test - public void test() throws Exception { - - } -} \ No newline at end of file diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index 3f5cd01a41..45928eec20 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.29.0' +implementation 'com.blankj:utilcode:1.30.0' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.29.0' +implementation 'com.blankj:utilcodex:1.30.0' ``` @@ -13,7 +13,7 @@ implementation 'com.blankj:utilcodex:1.29.0' * ### Activity 相关 -> [ActivityUtils.java][activity.java] -> [Demo][activity.demo] ``` -addActivityLifecycleCallbacks : 新增 Activity 生命周期监听 +addActivityLifecycleCallbacks : 增加 Activity 生命周期监听 removeActivityLifecycleCallbacks: 移除 Activity 生命周期监听 getAliveActivityByContext : 根据上下文获取存活的 Activity getActivityByContext : 根据上下文获取 Activity @@ -280,6 +280,18 @@ ClickUtils#OnDebouncingClickListener: 防抖点击监听器 ClickUtils#OnMultiClickListener : 连续点击监听器 ``` +* ### 剪贴板相关 -> [ClipboardUtils.java][clipboard.java] -> [Demo][clipboard.demo] +``` +copyText : 复制文本到剪贴板 +getText : 获取剪贴板的文本 +copyUri : 复制 uri 到剪贴板 +getUri : 获取剪贴板的 uri +copyIntent : 复制意图到剪贴板 +getIntent : 获取剪贴板的意图 +addChangedListener : 增加剪贴板监听器 +removeChangedListener: 移除剪贴板监听器 +``` + * ### 克隆相关 -> [CloneUtils.java][clone.java] -> [Test][clone.test] ``` deepClone: 深度克隆 @@ -319,8 +331,8 @@ transform : 对原集合进行转变 collect : 转变为新的集合 countMatches : 查找到匹配的元素个数 exists : 判断集合是否存在符合条件的元素 -addIgnoreNull : 新增元素如果不为空 -addAll : 新增多个元素 +addIgnoreNull : 增加元素如果不为空 +addAll : 增加多个元素 get : 获取集合元素 size : 获取集合个数 sizeIsEmpty : 判断个数是否为零 @@ -376,7 +388,10 @@ sp2px, px2sp : sp 与 px 互转 * ### 崩溃相关 -> [CrashUtils.java][crash.java] ``` -init: 初始化 +init : 初始化 +CrashInfo.addExtraHead: 增加额外头部 +CrashInfo.getThrowable: 获取崩溃异常 +CrashInfo.toString : 获取崩溃信息 ``` * ### 防抖相关 -> [DebouncingUtils.java][debouncing.java] @@ -500,7 +515,7 @@ getFsAvailableSize : 获取文件系统可用大小 * ### Fragment 相关 -> [FragmentUtils.java][fragment.java] -> [Demo][fragment.demo] ``` -add : 新增 fragment +add : 增加 fragment show : 显示 fragment hide : 隐藏 fragment showHide : 先显示后隐藏 fragment @@ -565,6 +580,7 @@ fastBlur : 快速模糊 renderScriptBlur : renderScript 模糊图片 stackBlur : stack 模糊图片 save : 保存图片 +save2Album : 保存图片到相册 isImage : 根据文件名判断文件是否为图片 getImageType : 获取图片类型 compressByScale : 按缩放压缩 @@ -603,47 +619,57 @@ clickBlankArea2HideSoftInput : 点击屏幕空白区域隐藏软键盘 * ### 语言相关 -> [LanguageUtils.java][language.java] -> [Demo][language.demo] ``` -applySystemLanguage : 应用系统语言 -applyLanguage : 应用语言 -isAppliedSystemLanguage: 判断是否使用系统语言 -isAppliedLanguage : 判断是否使用某语言 -getCurrentLocale : 获取当前语言 +applySystemLanguage : 设置系统语言 +applyLanguage : 设置语言 +isAppliedLanguage : 是否设置了语言 +getAppliedLanguage : 获取设置的语言 +getContextLanguage : 获取上下文的语言 +getAppContextLanguage : 获取应用上下文的语言 +getSystemLanguage : 获取系统的语言 +updateAppContextLanguage: 更新应用上下文语言 +attachBaseContext : 如果设置语言无效则在 Activity#attachBaseContext 调用它 ``` * ### 日志相关 -> [LogUtils.java][log.java] -> [Demo][log.demo] ``` -getConfig : 获取 log 配置 -Config.setLogSwitch : 设置 log 总开关 -Config.setConsoleSwitch : 设置 log 控制台开关 -Config.setGlobalTag : 设置 log 全局 tag -Config.setLogHeadSwitch : 设置 log 头部信息开关 -Config.setLog2FileSwitch : 设置 log 文件开关 -Config.setDir : 设置 log 文件存储目录 -Config.setFilePrefix : 设置 log 文件前缀 -Config.setBorderSwitch : 设置 log 边框开关 -Config.setSingleTagSwitch: 设置 log 单一 tag 开关(为美化 AS 3.1 的 Logcat) -Config.setConsoleFilter : 设置 log 控制台过滤器 -Config.setFileFilter : 设置 log 文件过滤器 -Config.setStackDeep : 设置 log 栈深度 -Config.setStackOffset : 设置 log 栈偏移 -Config.setSaveDays : 设置 log 可保留天数 -Config.addFormatter : 新增 log 格式化器 -log : 自定义 tag 的 type 日志 -v : tag 为类名的 Verbose 日志 -vTag : 自定义 tag 的 Verbose 日志 -d : tag 为类名的 Debug 日志 -dTag : 自定义 tag 的 Debug 日志 -i : tag 为类名的 Info 日志 -iTag : 自定义 tag 的 Info 日志 -w : tag 为类名的 Warn 日志 -wTag : 自定义 tag 的 Warn 日志 -e : tag 为类名的 Error 日志 -eTag : 自定义 tag 的 Error 日志 -a : tag 为类名的 Assert 日志 -aTag : 自定义 tag 的 Assert 日志 -file : log 到文件 -json : log 字符串之 json -xml : log 字符串之 xml +getConfig : 获取 log 配置 +Config.setLogSwitch : 设置 log 总开关 +Config.setConsoleSwitch : 设置 log 控制台开关 +Config.setGlobalTag : 设置 log 全局 tag +Config.setLogHeadSwitch : 设置 log 头部信息开关 +Config.setLog2FileSwitch : 设置 log 文件开关 +Config.setDir : 设置 log 文件存储目录 +Config.setFilePrefix : 设置 log 文件前缀 +Config.setBorderSwitch : 设置 log 边框开关 +Config.setSingleTagSwitch : 设置 log 单一 tag 开关(为美化 AS 3.1 的 Logcat) +Config.setConsoleFilter : 设置 log 控制台过滤器 +Config.setFileFilter : 设置 log 文件过滤器 +Config.setStackDeep : 设置 log 栈深度 +Config.setStackOffset : 设置 log 栈偏移 +Config.setSaveDays : 设置 log 可保留天数 +Config.addFormatter : 增加 log 格式化器 +Config.setFileWriter : 设置文件写入器 +Config.setOnConsoleOutputListener: 设置控制台输出监听器 +Config.setOnFileOutputListener : 设置文件输出监听器 +Config.addFileExtraHead : 增加 log 文件头部 +log : 自定义 tag 的 type 日志 +v : tag 为类名的 Verbose 日志 +vTag : 自定义 tag 的 Verbose 日志 +d : tag 为类名的 Debug 日志 +dTag : 自定义 tag 的 Debug 日志 +i : tag 为类名的 Info 日志 +iTag : 自定义 tag 的 Info 日志 +w : tag 为类名的 Warn 日志 +wTag : 自定义 tag 的 Warn 日志 +e : tag 为类名的 Error 日志 +eTag : 自定义 tag 的 Error 日志 +a : tag 为类名的 Assert 日志 +aTag : 自定义 tag 的 Assert 日志 +file : log 到文件 +json : log 字符串之 json +xml : log 字符串之 xml +getCurrentLogFilePath : 获取当前日志文件路径 +getLogFiles : 获取所有日志 ``` * ### Map 相关 -> [MapUtils.java][map.java] -> [Test][map.test] @@ -770,6 +796,13 @@ getCachePathExternalFirst : 优先获取外部缓存路径 * ### 权限相关 -> [PermissionUtils.java][permission.java] -> [Demo][permission.demo] ``` +permission : 设置请求权限 +permissionGroup : 设置请求权限组 +permission.explain : 设置权限请求前的解释 +permission.rationale : 设置拒绝权限后再次请求的回调接口 +permission.callback : 设置回调 +permission.theme : 设置主题 +permission.request : 开始请求 getPermissions : 获取应用权限 isGranted : 判断权限是否被授予 isGrantedWriteSettings : 判断修改系统权限是否被授予 @@ -777,11 +810,6 @@ requestWriteSettings : 申请修改系统权限 isGrantedDrawOverlays : 判断悬浮窗权限是否被授予 requestDrawOverlays : 申请悬浮窗权限 launchAppDetailsSettings: 打开应用具体设置 -permission : 设置请求权限 -rationale : 设置拒绝权限后再次请求的回调接口 -callback : 设置回调 -theme : 设置主题 -request : 开始请求 ``` * ### 手机相关 -> [PhoneUtils.java][phone.java] -> [Demo][phone.demo] @@ -1067,6 +1095,7 @@ toDBC : 转化为半角字符 toSBC : 转化为全角字符 getString : 获取字符资源 getStringArray : 获取字符数组资源 +format : 格式化字符串 ``` * ### 线程相关 -> [ThreadUtils.java][thread.java] -> [Test][thread.test] @@ -1138,16 +1167,23 @@ getZodiac : 获取星座 * ### 吐司相关 -> [ToastUtils.java][toast.java] -> [Demo][toast.demo] ``` -setGravity : 设置吐司位置 -setBgColor : 设置背景颜色 -setBgResource : 设置背景资源 -setMsgColor : 设置消息颜色 -setMsgTextSize : 设置消息字体大小 -showShort : 显示短时吐司 -showLong : 显示长时吐司 -showCustomShort: 显示短时自定义吐司 -showCustomLong : 显示长时自定义吐司 -cancel : 取消吐司显示 +make : 制作吐司 +make.setMode : 设置模式 +make.setGravity : 设置位置 +make.setBgColor : 设置背景颜色 +make.setBgResource : 设置背景资源 +make.setTextColor : 设置字体颜色 +make.setTextSize : 设置字体大小 +make.setDurationIsLong : 设置是否长时间显示 +make.setLeftIcon : 设置左侧图标 +make.setTopIcon : 设置顶部图标 +make.setRightIcon : 设置右侧图标 +make.setBottomIcon : 设置底部图标 +make.setNotUseSystemToast: 设置不使用系统吐司 +make.show : 显示吐司 +showShort : 显示短时吐司 +showLong : 显示长时吐司 +cancel : 取消吐司显示 ``` * ### 触摸相关 -> [TouchUtils.java][touch.java] @@ -1158,7 +1194,7 @@ setOnTouchListener: 设置触摸事件 * ### UI 消息相关 -> [UiMessageUtils.java][uiMessage.java] -> [Demo][uiMessage.demo] ``` send : 发送消息 -addListener : 新增消息监听器 +addListener : 增加消息监听器 removeListener: 移除消息监听器 ``` @@ -1193,6 +1229,15 @@ runOnUiThread : 在 UI 线程运行 runOnUiThreadDelayed: 在 UI 线程延迟运行 isLayoutRtl : 布局是否从右到左 fixScrollViewTopping: 修复 ScrollView 置顶问题 +layoutId2View : layoutId 转为 view +``` + +* ### 音量相关 -> [VolumeUtils.java][volume.java] +``` +getVolume : 获取音量 +setVolume : 设置音量 +getMaxVolume: 获取最大音量 +getMinVolume: 获取最小音量 ``` * ### 压缩相关 -> [ZipUtils.java][zip.java] -> [Test][zip.test] @@ -1262,6 +1307,9 @@ getComments : 获取压缩文件中的注释链表 [click.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClickUtils.java [click.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/click/ClickActivity.kt +[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClipboardUtils.java +[clipboard.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt + [clone.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/CloneUtils.java [clone.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/test/java/com/blankj/utilcode/util/CloneUtilsTest.java @@ -1417,5 +1465,8 @@ getComments : 获取压缩文件中的注释链表 [view.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java +[volume.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/VolumeUtils.java +[volume.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt + [zip.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ZipUtils.java [zip.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/test/java/com/blankj/utilcode/util/ZipUtilsTest.java diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index e29bf3dae1..27bb7c4990 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.29.0' +implementation 'com.blankj:utilcode:1.30.0' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.29.0' +implementation 'com.blankj:utilcodex:1.30.0' ``` @@ -280,6 +280,18 @@ ClickUtils#OnDebouncingClickListener ClickUtils#OnMultiClickListener ``` +* ### About Clipboard -> [ClipboardUtils.java][clipboard.java] -> [Demo][clipboard.demo] +``` +copyText +getText +copyUri +getUri +copyIntent +getIntent +addChangedListener +removeChangedListener +``` + * ### About Clone -> [CloneUtils.java][clone.java] -> [Test][clone.test] ``` deepClone @@ -342,6 +354,7 @@ string2Int int2RgbString int2ArgbString getRandomColor +isLightColor ``` * ### About Convert -> [ConvertUtils.java][convert.java] -> [Test][convert.test] @@ -376,6 +389,14 @@ sp2px, px2sp * ### About Crash -> [CrashUtils.java][crash.java] ``` init +CrashInfo.addExtraHead +CrashInfo.getThrowable +CrashInfo.toString +``` + +* ### About Debouncing -> [DebouncingUtils.java][debouncing.java] +``` +isValid ``` * ### About Device -> [DeviceUtils.java][device.java] -> [Demo][device.demo] @@ -559,6 +580,7 @@ fastBlur renderScriptBlur stackBlur save +save2Album isImage getImageType compressByScale @@ -576,6 +598,7 @@ getLaunchAppIntent getLaunchAppDetailsSettingsIntent getShareTextIntent getShareImageIntent +getShareTextImageIntent getComponentIntent getShutdownIntent getCaptureIntent @@ -598,9 +621,13 @@ clickBlankArea2HideSoftInput ``` applySystemLanguage applyLanguage -isAppliedSystemLanguage isAppliedLanguage -getCurrentLocale +getAppliedLanguage +getContextLanguage +getAppContextLanguage +getSystemLanguage +updateAppContextLanguage +attachBaseContext ``` * ### About Log -> [LogUtils.java][log.java] -> [Demo][log.demo] @@ -621,6 +648,10 @@ Config.setStackDeep Config.setStackOffset Config.setSaveDays Config.addFormatter +Config.setFileWriter +Config.setOnConsoleOutputListener +Config.setOnFileOutputListener +Config.addFileExtraHead log v vTag @@ -637,6 +668,8 @@ aTag file json xml +getCurrentLogFilePath +getLogFiles ``` * ### About Map -> [MapUtils.java][map.java] -> [Test][map.test] @@ -763,6 +796,13 @@ getCachePathExternalFirst * ### About Permission -> [PermissionUtils.java][permission.java] -> [Demo][permission.demo] ``` +permission +permissionGroup +permission.explain +permission.rationale +permission.callback +permission.theme +permission.request getPermissions isGranted isGrantedWriteSettings @@ -770,11 +810,6 @@ requestWriteSettings isGrantedDrawOverlays requestDrawOverlays launchAppDetailsSettings -permission -rationale -callback -theme -request ``` * ### About Phone -> [PhoneUtils.java][phone.java] -> [Demo][phone.demo] @@ -1060,6 +1095,7 @@ toDBC toSBC getString getStringArray +format ``` * ### About Thread -> [ThreadUtils.java][thread.java] -> [Test][thread.test] @@ -1131,15 +1167,22 @@ getZodiac * ### About Toast -> [ToastUtils.java][toast.java] -> [Demo][toast.demo] ``` -setGravity -setBgColor -setBgResource -setMsgColor -setMsgTextSize +make +make.setMode +make.setGravity +make.setBgColor +make.setBgResource +make.setTextColor +make.setTextSize +make.setDurationIsLong +make.setLeftIcon +make.setTopIcon +make.setRightIcon +make.setBottomIcon +make.setNotUseSystemToast +make.show showShort showLong -showCustomShort -showCustomLong cancel ``` @@ -1186,6 +1229,15 @@ runOnUiThread runOnUiThreadDelayed isLayoutRtl fixScrollViewTopping +layoutId2View +``` + +* ### About Volume -> [VolumeUtils.java][volume.java] +``` +getVolume +setVolume +getMaxVolume +getMinVolume ``` * ### About Zip -> [ZipUtils.java][zip.java] -> [Test][zip.test] @@ -1252,6 +1304,9 @@ getComments [click.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClickUtils.java [click.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/click/ClickActivity.kt +[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ClipboardUtils.java +[clipboard.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt + [clone.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/CloneUtils.java [clone.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/test/java/com/blankj/utilcode/util/CloneUtilsTest.java @@ -1268,6 +1323,8 @@ getComments [crash.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/CrashUtils.java +[debouncing.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java + [device.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/DeviceUtils.java [device.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt @@ -1405,5 +1462,8 @@ getComments [view.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java +[volume.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/VolumeUtils.java +[volume.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt + [zip.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ZipUtils.java [zip.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/test/java/com/blankj/utilcode/util/ZipUtilsTest.java diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java index ed92d88f0f..671b654bd9 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java @@ -20,58 +20,62 @@ @SuppressLint("InlinedApi") public final class PermissionConstants { - public static final String CALENDAR = "CALENDAR"; - public static final String CAMERA = "CAMERA"; - public static final String CONTACTS = "CONTACTS"; - public static final String LOCATION = "LOCATION"; - public static final String MICROPHONE = "MICROPHONE"; - public static final String PHONE = "PHONE"; - public static final String SENSORS = "SENSORS"; - public static final String SMS = "SMS"; - public static final String STORAGE = "STORAGE"; + public static final String CALENDAR = "CALENDAR"; + public static final String CAMERA = "CAMERA"; + public static final String CONTACTS = "CONTACTS"; + public static final String LOCATION = "LOCATION"; + public static final String MICROPHONE = "MICROPHONE"; + public static final String PHONE = "PHONE"; + public static final String SENSORS = "SENSORS"; + public static final String SMS = "SMS"; + public static final String STORAGE = "STORAGE"; + public static final String ACTIVITY_RECOGNITION = "ACTIVITY_RECOGNITION"; - private static final String[] GROUP_CALENDAR = { + private static final String[] GROUP_CALENDAR = { permission.READ_CALENDAR, permission.WRITE_CALENDAR }; - private static final String[] GROUP_CAMERA = { + private static final String[] GROUP_CAMERA = { permission.CAMERA }; - private static final String[] GROUP_CONTACTS = { + private static final String[] GROUP_CONTACTS = { permission.READ_CONTACTS, permission.WRITE_CONTACTS, permission.GET_ACCOUNTS }; - private static final String[] GROUP_LOCATION = { + private static final String[] GROUP_LOCATION = { permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION }; - private static final String[] GROUP_MICROPHONE = { + private static final String[] GROUP_MICROPHONE = { permission.RECORD_AUDIO }; - private static final String[] GROUP_PHONE = { + private static final String[] GROUP_PHONE = { permission.READ_PHONE_STATE, permission.READ_PHONE_NUMBERS, permission.CALL_PHONE, permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.ADD_VOICEMAIL, permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS, permission.ANSWER_PHONE_CALLS }; - private static final String[] GROUP_PHONE_BELOW_O = { + private static final String[] GROUP_PHONE_BELOW_O = { permission.READ_PHONE_STATE, permission.READ_PHONE_NUMBERS, permission.CALL_PHONE, permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.ADD_VOICEMAIL, permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS }; - private static final String[] GROUP_SENSORS = { + private static final String[] GROUP_SENSORS = { permission.BODY_SENSORS }; - private static final String[] GROUP_SMS = { + private static final String[] GROUP_SMS = { permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS, permission.RECEIVE_WAP_PUSH, permission.RECEIVE_MMS, }; - private static final String[] GROUP_STORAGE = { + private static final String[] GROUP_STORAGE = { permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE, }; + private static final String[] GROUP_ACTIVITY_RECOGNITION = { + permission.ACTIVITY_RECOGNITION, + }; @StringDef({CALENDAR, CAMERA, CONTACTS, LOCATION, MICROPHONE, PHONE, SENSORS, SMS, STORAGE,}) @Retention(RetentionPolicy.SOURCE) - public @interface Permission { + public @interface PermissionGroup { } - public static String[] getPermissions(@Permission final String permission) { + public static String[] getPermissions(@PermissionGroup final String permission) { if (permission == null) return new String[0]; switch (permission) { case CALENDAR: @@ -96,6 +100,8 @@ public static String[] getPermissions(@Permission final String permission) { return GROUP_SMS; case STORAGE: return GROUP_STORAGE; + case ACTIVITY_RECOGNITION: + return GROUP_ACTIVITY_RECOGNITION; } return new String[]{permission}; } 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..c4c2e0a8a5 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 @@ -39,6 +39,15 @@ private ActivityUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } + /** + * Add callbacks of activity lifecycle. + * + * @param callbacks The callbacks. + */ + public static void addActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) { + UtilsBridge.addActivityLifecycleCallbacks(callbacks); + } + /** * Add callbacks of activity lifecycle. * @@ -50,6 +59,15 @@ public static void addActivityLifecycleCallbacks(final Activity activity, UtilsBridge.addActivityLifecycleCallbacks(activity, callbacks); } + /** + * Remove callbacks of activity lifecycle. + * + * @param callbacks The callbacks. + */ + public static void removeActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) { + UtilsBridge.removeActivityLifecycleCallbacks(callbacks); + } + /** * Remove callbacks of activity lifecycle. * 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..3a5ec1f12b 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,7 +2,6 @@ import android.content.res.Resources; import android.util.DisplayMetrics; -import android.util.Log; import java.lang.reflect.Field; import java.util.ArrayList; @@ -145,7 +144,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/AppUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/AppUtils.java index f1a33238ab..9ba8830644 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,5 @@ package com.blankj.utilcode.util; -import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; @@ -633,8 +632,8 @@ 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) { 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 7f96cce7dd..0092763b12 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 @@ -13,6 +13,7 @@ import android.support.annotation.RequiresApi; import android.support.annotation.RequiresPermission; import android.support.v4.widget.DrawerLayout; +import android.util.Log; import android.util.TypedValue; import android.view.Display; import android.view.KeyCharacterMap; @@ -56,7 +57,7 @@ private BarUtils() { * @return the status bar's height */ public static int getStatusBarHeight() { - Resources resources = Resources.getSystem(); + Resources resources = Utils.getApp().getResources(); int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); return resources.getDimensionPixelSize(resourceId); } @@ -432,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; @@ -482,7 +483,7 @@ private static void invokePanels(final String methodName) { * @return the navigation bar's height */ public static int getNavBarHeight() { - Resources res = Resources.getSystem(); + Resources res = Utils.getApp().getResources(); int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId != 0) { return res.getDimensionPixelSize(resourceId); 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 87138eada4..adb88cc697 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,7 +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; @@ -31,8 +30,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,7 +56,7 @@ 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(tag, className, funName, paramType, paramName, sticky, threadMode, priority)); 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/CrashUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CrashUtils.java index dd049e7e77..8154d9e069 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,13 @@ package com.blankj.utilcode.util; import android.annotation.SuppressLint; -import android.os.Build; import android.support.annotation.NonNull; import java.io.File; import java.lang.Thread.UncaughtExceptionHandler; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Map; /** *
@@ -99,24 +99,12 @@ 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();
-                final String crashFile = dirPath + time + ".txt";
-                UtilsBridge.writeFileFromString(crashFile, crashInfo, true);
-
+                CrashInfo info = new CrashInfo(time, e);
                 if (onCrashListener != null) {
-                    onCrashListener.onCrash(crashInfo, e);
+                    onCrashListener.onCrash(info);
                 }
+                final String crashFile = dirPath + time + ".txt";
+                UtilsBridge.writeFileFromString(crashFile, info.toString(), true);
 
                 if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) {
                     DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(t, e);
@@ -130,6 +118,35 @@ 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(Map extraHead) {
+            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
index faac477b22..c9f2c8ff79 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java
@@ -45,9 +45,6 @@ public static boolean isValid(@NonNull final View view) {
      * @return {@code true}: yes
{@code false}: no */ public static boolean isValid(@NonNull final View view, final long duration) { - if (view == null) { - throw new IllegalArgumentException("The view is null."); - } return isValid(String.valueOf(view.hashCode()), duration); } 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 40de5ef5bb..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 @@ -11,17 +11,12 @@ import java.security.KeyFactory; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; 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; @@ -1132,19 +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) { - e.printStackTrace(); - } catch (NoSuchProviderException e) { + } catch (Exception e) { e.printStackTrace(); } return null; 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/ImageUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ImageUtils.java index 9e27fbde73..242b9dcfd5 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 @@ -14,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; @@ -39,7 +40,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; -import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.View; @@ -191,23 +191,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; @@ -341,15 +340,7 @@ public static Bitmap getBitmap(final byte[] data, * @return bitmap */ public static Bitmap getBitmap(@DrawableRes final int resId) { - Drawable drawable = ContextCompat.getDrawable(Utils.getApp(), resId); - Canvas canvas = new Canvas(); - Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), - Bitmap.Config.ARGB_8888); - canvas.setBitmap(bitmap); - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - drawable.draw(canvas); - return bitmap; + return BitmapFactory.decodeResource(Utils.getApp().getResources(), resId); } /** @@ -792,11 +783,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. * @@ -809,7 +816,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; @@ -823,14 +849,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; @@ -846,12 +874,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. * @@ -863,7 +925,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) { @@ -879,7 +941,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); } @@ -894,7 +956,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); @@ -912,11 +974,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(); @@ -930,10 +1014,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; } @@ -1659,12 +1745,23 @@ 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, @@ -1672,6 +1769,15 @@ public static File save2Album(final Bitmap src, 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, @@ -1679,6 +1785,16 @@ public static File save2Album(final Bitmap src, 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, 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..ea40ac3162 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; @@ -191,7 +189,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 +205,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 38d08eff2d..7f95fdee75 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 @@ -143,7 +143,7 @@ public static void hideSoftInput(@NonNull final View view) { * @param activity The activity. */ public static void hideSoftInputByToggle(final Activity activity) { - long nowMillis = SystemClock.uptimeMillis(); + long nowMillis = SystemClock.elapsedRealtime(); long delta = nowMillis - millis; if (Math.abs(delta) > 500 && KeyboardUtils.isSoftInputVisible(activity)) { KeyboardUtils.toggleSoftInput(); 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 d0ba85d243..dae5c97bfe 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,21 +1,15 @@ 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.support.annotation.Nullable; import android.text.TextUtils; -import android.util.DisplayMetrics; import android.util.Log; -import java.lang.reflect.Field; import java.util.Locale; /** @@ -37,206 +31,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); + applySystemLanguage(false); } /** * Apply the system language. * - * @param activityClz The class 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 Class activityClz) { - applyLanguage(Resources.getSystem().getConfiguration().locale, activityClz, true, true); - } - - /** - * Apply the system language. - * - * @param activityClassName The full class name of activity will be started after apply system language. - */ - 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(locale)) 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 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 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 { - UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, locale2String(locale)); + /** + * 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); - - 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 context. + * + * @return the locale of context + */ + public static Locale getContextLanguage(Context context) { + return getLocal(context.getResources().getConfiguration()); } /** - * Return whether applied the system language by {@link LanguageUtils}. + * Return the locale of applicationContext. * - * @return {@code true}: yes
{@code false}: no + * @return the locale of applicationContext */ - public static boolean isAppliedSystemLanguage() { - return VALUE_FOLLOW_SYSTEM.equals(UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE)); + public static Locale getAppContextLanguage() { + return getContextLanguage(Utils.getApp()); } /** - * Return whether applied the language by {@link LanguageUtils}. + * Return the locale of system * - * @return {@code true}: yes
{@code false}: no + * @return the locale of system */ - public static boolean isAppliedLanguage() { - return !TextUtils.isEmpty(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. * - * @param locale The locale. - * @return {@code true}: yes
{@code false}: no + * @param destLocale The dest locale. + * @param consumer The consumer. */ - public static boolean isAppliedLanguage(Locale locale) { - final String spLocale = UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE); - if (TextUtils.isEmpty(spLocale)) { - return false; - } - if (VALUE_FOLLOW_SYSTEM.equals(spLocale)) { - return false; + public static void updateAppContextLanguage(@NonNull Locale destLocale, @Nullable Utils.Consumer consumer) { + 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); } - Locale settingLocale = string2Locale(spLocale); - if (settingLocale == null) return false; - return isSameLocale(settingLocale, locale); } /** - * 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) { + 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); } - Locale settingLocale = string2Locale(spLocale); - if (settingLocale == null) return; - updateLanguage(Utils.getApp(), settingLocale); - updateLanguage(activity, settingLocale); + if (destLocal == null) return; + + updateConfiguration(activity, destLocal); + updateConfiguration(Utils.getApp(), destLocal); + } + + private static void updateConfiguration(Context context, Locale destLocal) { + Resources resources = context.getResources(); + Configuration config = resources.getConfiguration(); + setLocal(config, destLocal); + resources.updateConfiguration(config, resources.getDisplayMetrics()); } private static String locale2String(Locale locale) { - String localLanguage = locale.getLanguage(); - String localCountry = locale.getCountry(); + 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) { - String[] language_country = str.split("\\$"); - if (language_country.length != 2) { + Locale locale = string2LocaleReal(str); + if (locale == null) { Log.e("LanguageUtils", "The string of " + str + " is not in the correct format."); - return null; + UtilsBridge.getSpUtils4Utils().remove(KEY_LOCALE); } - return new Locale(language_country[0], language_country[1]); + return locale; } + private static Locale string2LocaleReal(String str) { + if (!isRightFormatLocalStr(str)) { + return null; + } - private static void updateLanguage(final Context context, Locale locale) { - Resources resources = context.getResources(); - Configuration config = resources.getConfiguration(); - Locale contextLocale = config.locale; - if (isSameLocale(contextLocale, locale)) { - return; + try { + int splitIndex = str.indexOf("$"); + return new Locale(str.substring(0, splitIndex), str.substring(splitIndex + 1)); + } catch (Exception ignore) { + return null; } - 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) {/**/} + } + + 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; } - } else { - config.locale = locale; } - resources.updateConfiguration(config, dm); + 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 { + return configuration.locale; + } + } + + 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..ad254474db 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 @@ -36,6 +36,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; @@ -228,6 +229,10 @@ public void run() { } } + public static String getCurrentLogFilePath() { + return getCurrentLogFilePath(new Date()); + } + public static List getLogFiles() { String dir = CONFIG.getDir(); File logDir = new File(dir); @@ -379,16 +384,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 +416,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 +461,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 +598,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 +608,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 +760,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 +850,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 +891,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 2ea696a6a3..e6ec4eec2a 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 @@ -159,7 +159,7 @@ public void onServiceConnected(ComponentName name, IBinder service) { try { mServer.send(msg); } catch (RemoteException e) { - Log.e("MessengerUtils", "onServiceConnected: ", e); + e.printStackTrace(); } sendCachedMsg2Server(); } @@ -205,7 +205,7 @@ void unbind() { try { mServer.send(msg); } catch (RemoteException e) { - Log.e("MessengerUtils", "unbind: ", e); + e.printStackTrace(); } try { Utils.getApp().unbindService(mConn); @@ -242,7 +242,7 @@ private boolean send2Server(Bundle bundle) { mServer.send(msg); return true; } catch (RemoteException e) { - Log.e("MessengerUtils", "send2Server: ", e); + e.printStackTrace(); return false; } } 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 9b6f36a1a8..f9ba566cc9 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 @@ -15,7 +15,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.format.Formatter; -import android.util.Log; import java.lang.reflect.Method; import java.net.InetAddress; @@ -227,8 +226,8 @@ public static boolean isAvailableByDns(final String domain) { return inetAddress != null; } catch (UnknownHostException e) { e.printStackTrace(); + return false; } - return false; } /** @@ -251,7 +250,7 @@ public static boolean getMobileDataEnabled() { return (boolean) getMobileDataEnabledMethod.invoke(tm); } } catch (Exception e) { - Log.e("NetworkUtils", "getMobileDataEnabled: ", e); + e.printStackTrace(); } return false; } 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 a550bf2820..2e3a985124 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 @@ -27,7 +27,7 @@ import java.util.List; import java.util.Set; -import static com.blankj.utilcode.constant.PermissionConstants.Permission; +import static com.blankj.utilcode.constant.PermissionConstants.PermissionGroup; /** *
@@ -42,6 +42,7 @@ public final class PermissionUtils {
     private static PermissionUtils sInstance;
 
     private String[]            mPermissionsParam;
+    private OnExplainListener   mOnExplainListener;
     private OnRationaleListener mOnRationaleListener;
     private SingleCallback      mSingleCallback;
     private SimpleCallback      mSimpleCallback;
@@ -89,7 +90,7 @@ public static List getPermissions(final String packageName) {
      * @param permissions The permissions.
      * @return {@code true}: yes
{@code false}: no */ - public static boolean isGranted(@Permission final String... permissions) { + public static boolean isGranted(final String... permissions) { Pair, List> requestAndDeniedPermissions = getRequestAndDeniedPermissions(permissions); List deniedPermissions = requestAndDeniedPermissions.second; if (!deniedPermissions.isEmpty()) { @@ -208,7 +209,17 @@ public static void launchAppDetailsSettings() { * @param permissions The permissions. * @return the single {@link PermissionUtils} instance */ - public static PermissionUtils permission(@Permission final String... permissions) { + public static PermissionUtils permissionGroup(@PermissionGroup final String... permissions) { + return new PermissionUtils(permissions); + } + + /** + * Set the permissions. + * + * @param permissions The permissions. + * @return the single {@link PermissionUtils} instance + */ + public static PermissionUtils permission(final String... permissions) { return new PermissionUtils(permissions); } @@ -217,6 +228,17 @@ private PermissionUtils(final String... permissions) { sInstance = this; } + /** + * Set explain listener. + * + * @param listener The explain listener. + * @return the single {@link PermissionUtils} instance + */ + public PermissionUtils explain(final OnExplainListener listener) { + mOnExplainListener = listener; + return this; + } + /** * Set rationale listener. * @@ -416,25 +438,41 @@ public void accept(Intent data) { } @Override - public void onCreated(final UtilsTransActivity activity, @Nullable Bundle savedInstanceState) { + public void onCreated(@NonNull final UtilsTransActivity activity, @Nullable Bundle savedInstanceState) { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); int type = activity.getIntent().getIntExtra(TYPE, -1); if (type == TYPE_RUNTIME) { if (sInstance == null) { - Log.e("PermissionUtils", "request permissions failed"); + Log.e("PermissionUtils", "sInstance is null."); + activity.finish(); + return; + } + if (sInstance.mPermissionsRequest == null) { + Log.e("PermissionUtils", "mPermissionsRequest is null."); + activity.finish(); + return; + } + if (sInstance.mPermissionsRequest.size() <= 0) { + Log.e("PermissionUtils", "mPermissionsRequest's size is no more than 0."); activity.finish(); return; } if (sInstance.mThemeCallback != null) { sInstance.mThemeCallback.onActivityCreate(activity); } - if (sInstance.shouldRationale(activity, new Runnable() { - @Override - public void run() { - requestPermissions(activity); - } - })) { + if (sInstance.mOnExplainListener != null) { + sInstance.mOnExplainListener.explain(activity, sInstance.mPermissionsRequest, new OnExplainListener.ShouldRequest() { + @Override + public void start(boolean start) { + if (!start) { + activity.finish(); + } else { + requestPermissions(activity); + } + } + }); + sInstance.mOnExplainListener = null; return; } requestPermissions(activity); @@ -450,22 +488,23 @@ public void run() { } } - private void requestPermissions(Activity activity) { - if (sInstance.mPermissionsRequest != null) { - int size = sInstance.mPermissionsRequest.size(); - if (size <= 0) { - activity.finish(); - return; + private void requestPermissions(final UtilsTransActivity activity) { + if (sInstance.shouldRationale(activity, new Runnable() { + @Override + public void run() { + activity.requestPermissions(sInstance.mPermissionsRequest.toArray(new String[0]), 1); } - activity.requestPermissions(sInstance.mPermissionsRequest.toArray(new String[size]), 1); + })) { + return; } + activity.requestPermissions(sInstance.mPermissionsRequest.toArray(new String[0]), 1); } @Override - public void onRequestPermissionsResult(UtilsTransActivity activity, + public void onRequestPermissionsResult(@NonNull UtilsTransActivity activity, int requestCode, - String[] permissions, - int[] grantResults) { + @NonNull String[] permissions, + @NonNull int[] grantResults) { activity.finish(); if (sInstance != null && sInstance.mPermissionsRequest != null) { sInstance.onRequestPermissionsResult(activity); @@ -474,13 +513,13 @@ public void onRequestPermissionsResult(UtilsTransActivity activity, @Override - public boolean dispatchTouchEvent(UtilsTransActivity activity, MotionEvent ev) { + public boolean dispatchTouchEvent(@NonNull UtilsTransActivity activity, MotionEvent ev) { activity.finish(); return true; } @Override - public void onDestroy(final UtilsTransActivity activity) { + public void onDestroy(@NonNull final UtilsTransActivity activity) { if (currentRequestCode != -1) { checkRequestCallback(currentRequestCode); currentRequestCode = -1; @@ -489,7 +528,7 @@ public void onDestroy(final UtilsTransActivity activity) { } @Override - public void onActivityResult(UtilsTransActivity activity, int requestCode, int resultCode, Intent data) { + public void onActivityResult(@NonNull UtilsTransActivity activity, int requestCode, int resultCode, Intent data) { activity.finish(); } @@ -518,9 +557,18 @@ private void checkRequestCallback(int requestCode) { // interface /////////////////////////////////////////////////////////////////////////// + public interface OnExplainListener { + + void explain(@NonNull UtilsTransActivity activity, @NonNull List denied, @NonNull ShouldRequest shouldRequest); + + interface ShouldRequest { + void start(boolean start); + } + } + public interface OnRationaleListener { - void rationale(UtilsTransActivity activity, ShouldRequest shouldRequest); + void rationale(@NonNull UtilsTransActivity activity, @NonNull ShouldRequest shouldRequest); interface ShouldRequest { void again(boolean again); @@ -546,6 +594,6 @@ public interface FullCallback { } public interface ThemeCallback { - void onActivityCreate(Activity activity); + void onActivityCreate(@NonNull Activity activity); } } \ No newline at end of file diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java index 079d138eea..b5cad7ef99 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java @@ -237,27 +237,12 @@ public static Bitmap screenShot(@NonNull final Activity activity) { */ public static Bitmap screenShot(@NonNull final Activity activity, boolean isDeleteStatusBar) { View decorView = activity.getWindow().getDecorView(); - boolean drawingCacheEnabled = decorView.isDrawingCacheEnabled(); - boolean willNotCacheDrawing = decorView.willNotCacheDrawing(); - decorView.setDrawingCacheEnabled(true); - decorView.setWillNotCacheDrawing(false); - Bitmap bmp = decorView.getDrawingCache(); - if (bmp == null || bmp.isRecycled()) { - decorView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), - View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); - decorView.layout(0, 0, decorView.getMeasuredWidth(), decorView.getMeasuredHeight()); - decorView.buildDrawingCache(); - bmp = Bitmap.createBitmap(decorView.getDrawingCache()); - } - if (bmp == null || bmp.isRecycled()) return null; + Bitmap bmp = UtilsBridge.view2Bitmap(decorView); DisplayMetrics dm = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(dm); - Bitmap ret; if (isDeleteStatusBar) { - Resources resources = activity.getResources(); - int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); - int statusBarHeight = resources.getDimensionPixelSize(resourceId); - ret = Bitmap.createBitmap( + int statusBarHeight = UtilsBridge.getStatusBarHeight(); + return Bitmap.createBitmap( bmp, 0, statusBarHeight, @@ -265,12 +250,8 @@ public static Bitmap screenShot(@NonNull final Activity activity, boolean isDele dm.heightPixels - statusBarHeight ); } else { - ret = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels); + return Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels); } - decorView.destroyDrawingCache(); - decorView.setWillNotCacheDrawing(willNotCacheDrawing); - decorView.setDrawingCacheEnabled(drawingCacheEnabled); - return ret; } /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java index c3254e3d32..28efede8d4 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java @@ -4,6 +4,8 @@ import android.support.annotation.ArrayRes; import android.support.annotation.StringRes; +import java.util.IllegalFormatException; + /** *
  *     author: Blankj
@@ -117,7 +119,7 @@ public static int length(final CharSequence s) {
     public static String upperFirstLetter(final String s) {
         if (s == null || s.length() == 0) return "";
         if (!Character.isLowerCase(s.charAt(0))) return s;
-        return String.valueOf((char) (s.charAt(0) - 32)) + s.substring(1);
+        return (char) (s.charAt(0) - 32) + s.substring(1);
     }
 
     /**
@@ -202,11 +204,7 @@ public static String toSBC(final String s) {
      * @return the string value associated with a particular resource ID.
      */
     public static String getString(@StringRes int id) {
-        try {
-            return Utils.getApp().getResources().getString(id);
-        } catch (Resources.NotFoundException ignore) {
-            return "";
-        }
+        return getString(id, (Object[]) null);
     }
 
     /**
@@ -218,9 +216,10 @@ public static String getString(@StringRes int id) {
      */
     public static String getString(@StringRes int id, Object... formatArgs) {
         try {
-            return Utils.getApp().getString(id, formatArgs);
-        } catch (Resources.NotFoundException ignore) {
-            return "";
+            return format(Utils.getApp().getString(id), formatArgs);
+        } catch (Resources.NotFoundException e) {
+            e.printStackTrace();
+            return String.valueOf(id);
         }
     }
 
@@ -233,8 +232,30 @@ public static String getString(@StringRes int id, Object... formatArgs) {
     public static String[] getStringArray(@ArrayRes int id) {
         try {
             return Utils.getApp().getResources().getStringArray(id);
-        } catch (Resources.NotFoundException ignore) {
-            return new String[0];
+        } catch (Resources.NotFoundException e) {
+            e.printStackTrace();
+            return new String[]{String.valueOf(id)};
+        }
+    }
+
+    /**
+     * Format the string.
+     *
+     * @param str  The string.
+     * @param args The args.
+     * @return a formatted string.
+     */
+    public static String format(String str, Object... args) {
+        String text = str;
+        if (text != null) {
+            if (args != null && args.length > 0) {
+                try {
+                    text = String.format(str, args);
+                } catch (IllegalFormatException e) {
+                    e.printStackTrace();
+                }
+            }
         }
+        return text;
     }
 }
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java
index 3abb3b35ab..0bdd221a29 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java
@@ -2,32 +2,42 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.support.annotation.CallSuper;
 import android.support.annotation.ColorInt;
 import android.support.annotation.DrawableRes;
-import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.StringDef;
 import android.support.annotation.StringRes;
 import android.support.v4.app.NotificationManagerCompat;
-import android.util.Log;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
 import android.view.Gravity;
-import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
 import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import com.blankj.utilcode.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Field;
 
 /**
@@ -40,20 +50,49 @@
  */
 public final class ToastUtils {
 
-    private static final int    COLOR_DEFAULT = 0xFEFFFFFF;
-    private static final String NULL          = "null";
+    @StringDef({MODE.LIGHT, MODE.DARK})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MODE {
+        String LIGHT = "light";
+        String DARK  = "dark";
+    }
+
+    private static final String     TAG_TOAST           = "TAG_TOAST";
+    private static final int        COLOR_DEFAULT       = 0xFEFFFFFF;
+    private static final String     NULL                = "toast null";
+    private static final String     NOTHING             = "toast nothing";
+    private static final ToastUtils DEFAULT_TOAST_UTILS = make();
 
     private static IToast iToast;
-    private static int    sGravity     = -1;
-    private static int    sXOffset     = -1;
-    private static int    sYOffset     = -1;
-    private static int    sBgColor     = COLOR_DEFAULT;
-    private static int    sBgResource  = -1;
-    private static int    sMsgColor    = COLOR_DEFAULT;
-    private static int    sMsgTextSize = -1;
 
-    private ToastUtils() {
-        throw new UnsupportedOperationException("u can't instantiate me...");
+    private String     mMode;
+    private int        mGravity            = -1;
+    private int        mXOffset            = -1;
+    private int        mYOffset            = -1;
+    private int        mBgColor            = COLOR_DEFAULT;
+    private int        mBgResource         = -1;
+    private int        mTextColor          = COLOR_DEFAULT;
+    private int        mTextSize           = -1;
+    private boolean    isLong              = false;
+    private Drawable[] mIcons              = new Drawable[4];
+    private boolean    isNotUseSystemToast = false;
+
+    /**
+     * Make a toast.
+     *
+     * @return the single {@link ToastUtils} instance
+     */
+    public static ToastUtils make() {
+        return new ToastUtils();
+    }
+
+    /**
+     * @param mode The mode.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setMode(@MODE String mode) {
+        mMode = mode;
+        return this;
     }
 
     /**
@@ -62,47 +101,161 @@ private ToastUtils() {
      * @param gravity The gravity.
      * @param xOffset X-axis offset, in pixel.
      * @param yOffset Y-axis offset, in pixel.
+     * @return the single {@link ToastUtils} instance
      */
-    public static void setGravity(final int gravity, final int xOffset, final int yOffset) {
-        sGravity = gravity;
-        sXOffset = xOffset;
-        sYOffset = yOffset;
+    public final ToastUtils setGravity(final int gravity, final int xOffset, final int yOffset) {
+        mGravity = gravity;
+        mXOffset = xOffset;
+        mYOffset = yOffset;
+        return this;
     }
 
     /**
      * Set the color of background.
      *
      * @param backgroundColor The color of background.
+     * @return the single {@link ToastUtils} instance
      */
-    public static void setBgColor(@ColorInt final int backgroundColor) {
-        sBgColor = backgroundColor;
+    public final ToastUtils setBgColor(@ColorInt final int backgroundColor) {
+        mBgColor = backgroundColor;
+        return this;
     }
 
     /**
      * Set the resource of background.
      *
      * @param bgResource The resource of background.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setBgResource(@DrawableRes final int bgResource) {
+        mBgResource = bgResource;
+        return this;
+    }
+
+    /**
+     * Set the text color of toast.
+     *
+     * @param msgColor The text color of toast.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setTextColor(@ColorInt final int msgColor) {
+        mTextColor = msgColor;
+        return this;
+    }
+
+    /**
+     * Set the text size of toast.
+     *
+     * @param textSize The text size of toast.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setTextSize(final int textSize) {
+        mTextSize = textSize;
+        return this;
+    }
+
+    /**
+     * Set the toast for a long period of time.
+     *
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setDurationIsLong(boolean isLong) {
+        this.isLong = isLong;
+        return this;
+    }
+
+    /**
+     * Set the left icon of toast.
+     *
+     * @param resId The left icon resource identifier.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setLeftIcon(@DrawableRes int resId) {
+        return setLeftIcon(ContextCompat.getDrawable(Utils.getApp(), resId));
+    }
+
+    /**
+     * Set the left icon of toast.
+     *
+     * @param drawable The left icon drawable.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setLeftIcon(Drawable drawable) {
+        mIcons[0] = drawable;
+        return this;
+    }
+
+    /**
+     * Set the top icon of toast.
+     *
+     * @param resId The top icon resource identifier.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setTopIcon(@DrawableRes int resId) {
+        return setTopIcon(ContextCompat.getDrawable(Utils.getApp(), resId));
+    }
+
+    /**
+     * Set the top icon of toast.
+     *
+     * @param drawable The top icon drawable.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setTopIcon(Drawable drawable) {
+        mIcons[1] = drawable;
+        return this;
+    }
+
+    /**
+     * Set the right icon of toast.
+     *
+     * @param resId The right icon resource identifier.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setRightIcon(@DrawableRes int resId) {
+        return setRightIcon(ContextCompat.getDrawable(Utils.getApp(), resId));
+    }
+
+    /**
+     * Set the right icon of toast.
+     *
+     * @param drawable The right icon drawable.
+     * @return the single {@link ToastUtils} instance
+     */
+    public final ToastUtils setRightIcon(Drawable drawable) {
+        mIcons[2] = drawable;
+        return this;
+    }
+
+    /**
+     * Set the left bottom of toast.
+     *
+     * @param resId The bottom icon resource identifier.
+     * @return the single {@link ToastUtils} instance
      */
-    public static void setBgResource(@DrawableRes final int bgResource) {
-        sBgResource = bgResource;
+    public final ToastUtils setBottomIcon(int resId) {
+        return setBottomIcon(ContextCompat.getDrawable(Utils.getApp(), resId));
     }
 
     /**
-     * Set the color of message.
+     * Set the bottom icon of toast.
      *
-     * @param msgColor The color of message.
+     * @param drawable The bottom icon drawable.
+     * @return the single {@link ToastUtils} instance
      */
-    public static void setMsgColor(@ColorInt final int msgColor) {
-        sMsgColor = msgColor;
+    public final ToastUtils setBottomIcon(Drawable drawable) {
+        mIcons[3] = drawable;
+        return this;
     }
 
     /**
-     * Set the text size of message.
+     * Set not use system toast.
      *
-     * @param textSize The text size of message.
+     * @return the single {@link ToastUtils} instance
      */
-    public static void setMsgTextSize(final int textSize) {
-        sMsgTextSize = textSize;
+    public final ToastUtils setNotUseSystemToast() {
+        isNotUseSystemToast = true;
+        return this;
     }
 
     /**
@@ -110,8 +263,8 @@ public static void setMsgTextSize(final int textSize) {
      *
      * @param text The text.
      */
-    public static void showShort(final CharSequence text) {
-        show(text == null ? NULL : text, Toast.LENGTH_SHORT);
+    public final void show(final CharSequence text) {
+        show(text, getDuration(), this);
     }
 
     /**
@@ -119,8 +272,8 @@ public static void showShort(final CharSequence text) {
      *
      * @param resId The resource id for text.
      */
-    public static void showShort(@StringRes final int resId) {
-        show(resId, Toast.LENGTH_SHORT);
+    public final void show(@StringRes final int resId) {
+        show(UtilsBridge.getString(resId), getDuration(), this);
     }
 
     /**
@@ -129,8 +282,8 @@ public static void showShort(@StringRes final int resId) {
      * @param resId The resource id for text.
      * @param args  The args.
      */
-    public static void showShort(@StringRes final int resId, final Object... args) {
-        show(resId, Toast.LENGTH_SHORT, args);
+    public final void show(@StringRes final int resId, final Object... args) {
+        show(UtilsBridge.getString(resId, args), getDuration(), this);
     }
 
     /**
@@ -139,84 +292,133 @@ public static void showShort(@StringRes final int resId, final Object... args) {
      * @param format The format.
      * @param args   The args.
      */
-    public static void showShort(final String format, final Object... args) {
-        show(format, Toast.LENGTH_SHORT, args);
+    public final void show(final String format, final Object... args) {
+        show(UtilsBridge.format(format, args), getDuration(), this);
     }
 
     /**
-     * Show the toast for a long period of time.
+     * Show custom toast.
+     */
+    public final void show(final View view) {
+        show(view, getDuration(), this);
+    }
+
+    private int getDuration() {
+        return isLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
+    }
+
+    private View tryApplyUtilsToastView(final CharSequence text) {
+        if (!MODE.DARK.equals(mMode) && !MODE.LIGHT.equals(mMode)
+                && mIcons[0] == null && mIcons[1] == null && mIcons[2] == null && mIcons[3] == null) {
+            return null;
+        }
+
+        View toastView = UtilsBridge.layoutId2View(R.layout.utils_toast_view);
+        TextView messageTv = toastView.findViewById(android.R.id.message);
+        if (MODE.DARK.equals(mMode)) {
+            GradientDrawable bg = (GradientDrawable) toastView.getBackground().mutate();
+            bg.setColor(Color.parseColor("#BB000000"));
+            messageTv.setTextColor(Color.WHITE);
+        }
+        messageTv.setText(text);
+        if (mIcons[0] != null) {
+            View leftIconView = toastView.findViewById(R.id.utvLeftIconView);
+            ViewCompat.setBackground(leftIconView, mIcons[0]);
+            leftIconView.setVisibility(View.VISIBLE);
+        }
+        if (mIcons[1] != null) {
+            View topIconView = toastView.findViewById(R.id.utvTopIconView);
+            ViewCompat.setBackground(topIconView, mIcons[1]);
+            topIconView.setVisibility(View.VISIBLE);
+        }
+        if (mIcons[2] != null) {
+            View rightIconView = toastView.findViewById(R.id.utvRightIconView);
+            ViewCompat.setBackground(rightIconView, mIcons[2]);
+            rightIconView.setVisibility(View.VISIBLE);
+        }
+        if (mIcons[3] != null) {
+            View bottomIconView = toastView.findViewById(R.id.utvBottomIconView);
+            ViewCompat.setBackground(bottomIconView, mIcons[3]);
+            bottomIconView.setVisibility(View.VISIBLE);
+        }
+        return toastView;
+    }
+
+
+    /**
+     * Show the toast for a short period of time.
      *
      * @param text The text.
      */
-    public static void showLong(final CharSequence text) {
-        show(text == null ? NULL : text, Toast.LENGTH_LONG);
+    public static void showShort(final CharSequence text) {
+        show(text, Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show the toast for a long period of time.
+     * Show the toast for a short period of time.
      *
      * @param resId The resource id for text.
      */
-    public static void showLong(@StringRes final int resId) {
-        show(resId, Toast.LENGTH_LONG);
+    public static void showShort(@StringRes final int resId) {
+        show(UtilsBridge.getString(resId), Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show the toast for a long period of time.
+     * Show the toast for a short period of time.
      *
      * @param resId The resource id for text.
      * @param args  The args.
      */
-    public static void showLong(@StringRes final int resId, final Object... args) {
-        show(resId, Toast.LENGTH_LONG, args);
+    public static void showShort(@StringRes final int resId, final Object... args) {
+        show(UtilsBridge.getString(resId, args), Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show the toast for a long period of time.
+     * Show the toast for a short period of time.
      *
      * @param format The format.
      * @param args   The args.
      */
-    public static void showLong(final String format, final Object... args) {
-        show(format, Toast.LENGTH_LONG, args);
+    public static void showShort(final String format, final Object... args) {
+        show(UtilsBridge.format(format, args), Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show custom toast for a short period of time.
+     * Show the toast for a long period of time.
      *
-     * @param layoutId ID for an XML layout resource to load.
+     * @param text The text.
      */
-    public static View showCustomShort(@LayoutRes final int layoutId) {
-        return showCustomShort(getView(layoutId));
+    public static void showLong(final CharSequence text) {
+        show(text, Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show custom toast for a short period of time.
+     * Show the toast for a long period of time.
      *
-     * @param view The view of toast.
+     * @param resId The resource id for text.
      */
-    public static View showCustomShort(final View view) {
-        show(view, Toast.LENGTH_SHORT);
-        return view;
+    public static void showLong(@StringRes final int resId) {
+        show(UtilsBridge.getString(resId), Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show custom toast for a long period of time.
+     * Show the toast for a long period of time.
      *
-     * @param layoutId ID for an XML layout resource to load.
+     * @param resId The resource id for text.
+     * @param args  The args.
      */
-    public static View showCustomLong(@LayoutRes final int layoutId) {
-        return showCustomLong(getView(layoutId));
+    public static void showLong(@StringRes final int resId, final Object... args) {
+        show(UtilsBridge.getString(resId), Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS);
     }
 
     /**
-     * Show custom toast for a long period of time.
+     * Show the toast for a long period of time.
      *
-     * @param view The view of toast.
+     * @param format The format.
+     * @param args   The args.
      */
-    public static View showCustomLong(final View view) {
-        show(view, Toast.LENGTH_LONG);
-        return view;
+    public static void showLong(final String format, final Object... args) {
+        show(UtilsBridge.format(format, args), Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS);
     }
 
     /**
@@ -225,93 +427,79 @@ public static View showCustomLong(final View view) {
     public static void cancel() {
         if (iToast != null) {
             iToast.cancel();
+            iToast = null;
         }
     }
 
-    private static void show(final int resId, final int duration) {
-        show(resId, duration, (Object) null);
-    }
-
-    private static void show(final int resId, final int duration, final Object... args) {
-        try {
-            CharSequence text = Utils.getApp().getResources().getText(resId);
-            if (args != null && args.length > 0) {
-                text = String.format(text.toString(), args);
-            }
-            show(text, duration);
-        } catch (Exception ignore) {
-            show(String.valueOf(resId), duration);
-        }
+    private static void show(final CharSequence text, final int duration, final ToastUtils utils) {
+        show(null, getToastFriendlyText(text), duration, utils);
     }
 
-    private static void show(final String format, final int duration, final Object... args) {
-        String text = format;
-        if (text == null) {
-            text = NULL;
-        } else {
-            if (args != null && args.length > 0) {
-                text = String.format(format, args);
-            }
-        }
-        show(text, duration);
+    private static void show(final View view, final int duration, final ToastUtils utils) {
+        show(view, null, duration, utils);
     }
 
-    private static void show(final CharSequence text, final int duration) {
-        show(null, text, duration);
-    }
-
-    private static void show(final View view, final int duration) {
-        show(view, null, duration);
-    }
-
-    private static void show(@Nullable final View view, final CharSequence text, final int duration) {
+    private static void show(@Nullable final View view, final CharSequence text, final int duration, final ToastUtils utils) {
         UtilsBridge.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 cancel();
-                iToast = newToast();
+                iToast = newToast(utils);
                 if (view != null) {
-                    iToast.setView(view);
+                    iToast.setToastView(view);
                 } else {
-                    iToast.setMsgView(text);
+                    iToast.setToastView(text);
                 }
-                iToast.setDuration(duration);
-                if (sGravity != -1 || sXOffset != -1 || sYOffset != -1) {
-                    iToast.setGravity(sGravity, sXOffset, sYOffset);
-                }
-                iToast.show();
+                iToast.show(duration);
             }
         });
     }
 
+    private static CharSequence getToastFriendlyText(CharSequence src) {
+        CharSequence text = src;
+        if (text == null) {
+            text = NULL;
+        } else if (text.length() == 0) {
+            text = NOTHING;
+        }
+        return text;
+    }
 
-    private static IToast newToast() {
-        if (NotificationManagerCompat.from(Utils.getApp()).areNotificationsEnabled()) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+    private static IToast newToast(ToastUtils toastUtils) {
+        if (!toastUtils.isNotUseSystemToast) {
+            if (NotificationManagerCompat.from(Utils.getApp()).areNotificationsEnabled()) {
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+                    return new SystemToast(toastUtils);
+                }
                 if (!UtilsBridge.isGrantedDrawOverlays()) {
-                    return new SystemToast(new Toast(Utils.getApp()));
+                    return new SystemToast(toastUtils);
                 }
             }
         }
-        return new ToastWithoutNotification(new Toast(Utils.getApp()));
-    }
 
-    private static View getView(@LayoutRes final int layoutId) {
-        LayoutInflater inflate =
-                (LayoutInflater) Utils.getApp().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        return inflate.inflate(layoutId, null);
+        // no notification
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
+            return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_TOAST);
+        } else if (UtilsBridge.isGrantedDrawOverlays()) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+            } else {
+                new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_PHONE);
+            }
+        }
+        return new ActivityToast(toastUtils);
     }
 
-    static class SystemToast extends AbsToast {
+    static final class SystemToast extends AbsToast {
 
-        SystemToast(Toast toast) {
-            super(toast);
+        SystemToast(ToastUtils toastUtils) {
+            super(toastUtils);
             if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
                 try {
                     //noinspection JavaReflectionMemberAccess
                     Field mTNField = Toast.class.getDeclaredField("mTN");
                     mTNField.setAccessible(true);
-                    Object mTN = mTNField.get(toast);
+                    Object mTN = mTNField.get(mToast);
                     Field mTNmHandlerField = mTNField.getType().getDeclaredField("mHandler");
                     mTNmHandlerField.setAccessible(true);
                     Handler tnHandler = (Handler) mTNmHandlerField.get(mTN);
@@ -321,16 +509,12 @@ static class SystemToast extends AbsToast {
         }
 
         @Override
-        public void show() {
+        public void show(int duration) {
+            if (mToast == null) return;
+            mToast.setDuration(duration);
             mToast.show();
         }
 
-        @Override
-        public void cancel() {
-            mToast.cancel();
-            super.cancel();
-        }
-
         static class SafeHandler extends Handler {
             private Handler impl;
 
@@ -339,82 +523,38 @@ static class SafeHandler extends Handler {
             }
 
             @Override
-            public void handleMessage(Message msg) {
+            public void handleMessage(@NonNull Message msg) {
                 impl.handleMessage(msg);
             }
 
             @Override
-            public void dispatchMessage(Message msg) {
+            public void dispatchMessage(@NonNull Message msg) {
                 try {
                     impl.dispatchMessage(msg);
                 } catch (Exception e) {
-                    Log.e("ToastUtils", e.toString());
+                    e.printStackTrace();
                 }
             }
         }
     }
 
-    static class ToastWithoutNotification extends AbsToast {
+    static final class WindowManagerToast extends AbsToast {
 
         private WindowManager mWM;
 
-        private WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+        private WindowManager.LayoutParams mParams;
 
-        ToastWithoutNotification(Toast toast) {
-            super(toast);
+        private Utils.ActivityLifecycleCallbacks mActivityLifecycleCallbacks;
+
+        WindowManagerToast(ToastUtils toastUtils, int type) {
+            super(toastUtils);
+            mParams = new WindowManager.LayoutParams();
+            mParams.type = type;
         }
 
         @Override
-        public void show() {
+        public void show(final int duration) {
             if (mToast == null) return;
-            boolean isActivityContext = false;
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
-                mWM = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE);
-                mParams.type = WindowManager.LayoutParams.TYPE_TOAST;
-            } else if (UtilsBridge.isGrantedDrawOverlays()) {
-                mWM = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE);
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                    mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-                } else {
-                    mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
-                }
-            } else {
-                Context topActivityOrApp = UtilsBridge.getTopActivityOrApp();
-                if (!(topActivityOrApp instanceof Activity)) {
-                    Log.w("ToastUtils", "Couldn't get top Activity.");
-                    // try to use system toast
-                    new SystemToast(mToast).show();
-                    return;
-                }
-                Activity topActivity = (Activity) topActivityOrApp;
-                if (topActivity.isFinishing() || topActivity.isDestroyed()) {
-                    Log.w("ToastUtils", topActivity + " is useless");
-                    // try to use system toast
-                    new SystemToast(mToast).show();
-                    return;
-                }
-                isActivityContext = true;
-                mWM = topActivity.getWindowManager();
-                mParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-                UtilsBridge.addActivityLifecycleCallbacks(topActivity, getActivityLifecycleCallbacks());
-            }
-
-            setToastParams();
-
-            final long duration = mToast.getDuration() == Toast.LENGTH_SHORT ? 2000 : 3500;
-            if (isActivityContext) {
-                UtilsBridge.runOnUiThreadDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        setToast(duration);
-                    }
-                }, 300);
-            } else {
-                setToast(duration);
-            }
-        }
-
-        private void setToastParams() {
             mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
             mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
             mParams.format = PixelFormat.TRANSLUCENT;
@@ -437,9 +577,8 @@ private void setToastParams() {
             mParams.y = mToast.getYOffset();
             mParams.horizontalMargin = mToast.getHorizontalMargin();
             mParams.verticalMargin = mToast.getVerticalMargin();
-        }
 
-        private void setToast(long duration) {
+            mWM = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE);
             try {
                 if (mWM != null) {
                     mWM.addView(mToastView, mParams);
@@ -451,18 +590,7 @@ private void setToast(long duration) {
                 public void run() {
                     cancel();
                 }
-            }, duration);
-        }
-
-        private Utils.ActivityLifecycleCallbacks getActivityLifecycleCallbacks() {
-            return new Utils.ActivityLifecycleCallbacks() {
-                @Override
-                public void onActivityDestroyed(@NonNull Activity activity) {
-                    if (iToast == null) return;
-                    activity.getWindow().getDecorView().setVisibility(View.GONE);
-                    iToast.cancel();
-                }
-            };
+            }, duration == Toast.LENGTH_SHORT ? 2000 : 3500);
         }
 
         @Override
@@ -470,95 +598,205 @@ public void cancel() {
             try {
                 if (mWM != null) {
                     mWM.removeViewImmediate(mToastView);
+                    mWM = null;
                 }
             } catch (Exception ignored) {/**/}
-            mWM = null;
             super.cancel();
         }
     }
 
-    static abstract class AbsToast implements IToast {
+    static final class ActivityToast extends AbsToast {
 
-        protected Toast mToast;
-        protected View  mToastView;
+        private static int sShowingIndex = 0;
 
-        AbsToast(Toast toast) {
-            mToast = toast;
-        }
+        private Utils.ActivityLifecycleCallbacks mActivityLifecycleCallbacks;
 
-        @Override
-        public void setView(View view) {
-            mToastView = view;
-            mToast.setView(mToastView);
+        ActivityToast(ToastUtils toastUtils) {
+            super(toastUtils);
         }
 
         @Override
-        public void setMsgView(CharSequence text) {
-            mToastView = mToast.getView();
-            if (mToastView == null || mToastView.findViewById(android.R.id.message) == null) {
-                mToastView = ToastUtils.getView(R.layout.toast_layout);
-                mToast.setView(mToastView);
+        public void show(int duration) {
+            if (mToast == null) return;
+            if (!UtilsBridge.isAppForeground()) {
+                // try to use system toast
+                showSystemToast(duration);
+                return;
             }
+            boolean hasAliveActivity = false;
+            for (final Activity activity : UtilsBridge.getActivityList()) {
+                if (!UtilsBridge.isActivityAlive(activity)) {
+                    continue;
+                }
+                hasAliveActivity = true;
+                showWithActivity(activity, sShowingIndex, true);
+            }
+            if (hasAliveActivity) {
+                registerLifecycleCallback();
+                UtilsBridge.runOnUiThreadDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        cancel();
+                    }
+                }, duration == Toast.LENGTH_SHORT ? 2000 : 3500);
 
-            TextView tvMessage = mToastView.findViewById(android.R.id.message);
-            tvMessage.setText(text);
-            if (sMsgColor != COLOR_DEFAULT) {
-                tvMessage.setTextColor(sMsgColor);
+                ++sShowingIndex;
+            } else {
+                // try to use system toast
+                showSystemToast(duration);
             }
-            if (sMsgTextSize != -1) {
-                tvMessage.setTextSize(sMsgTextSize);
+        }
+
+        @Override
+        public void cancel() {
+            if (isShowing()) {
+                unregisterLifecycleCallback();
+                for (Activity activity : UtilsBridge.getActivityList()) {
+                    if (!UtilsBridge.isActivityAlive(activity)) {
+                        continue;
+                    }
+                    final Window window = activity.getWindow();
+                    if (window != null) {
+                        ViewGroup decorView = (ViewGroup) window.getDecorView();
+                        View toastView = decorView.findViewWithTag(TAG_TOAST + (sShowingIndex - 1));
+                        if (toastView != null) {
+                            try {
+                                decorView.removeView(toastView);
+                            } catch (Exception ignored) {/**/}
+                        }
+                    }
+                }
             }
-            setBg(tvMessage);
-        }
-
-        private void setBg(final TextView tvMsg) {
-            if (sBgResource != -1) {
-                mToastView.setBackgroundResource(sBgResource);
-                tvMsg.setBackgroundColor(Color.TRANSPARENT);
-            } else if (sBgColor != COLOR_DEFAULT) {
-                Drawable tvBg = mToastView.getBackground();
-                Drawable msgBg = tvMsg.getBackground();
-                if (tvBg != null && msgBg != null) {
-                    tvBg.setColorFilter(new PorterDuffColorFilter(sBgColor, PorterDuff.Mode.SRC_IN));
-                    tvMsg.setBackgroundColor(Color.TRANSPARENT);
-                } else if (tvBg != null) {
-                    tvBg.setColorFilter(new PorterDuffColorFilter(sBgColor, PorterDuff.Mode.SRC_IN));
-                } else if (msgBg != null) {
-                    msgBg.setColorFilter(new PorterDuffColorFilter(sBgColor, PorterDuff.Mode.SRC_IN));
-                } else {
-                    mToastView.setBackgroundColor(sBgColor);
+            super.cancel();
+        }
+
+        private void showSystemToast(int duration) {
+            SystemToast systemToast = new SystemToast(mToastUtils);
+            systemToast.mToast = mToast;
+            systemToast.show(duration);
+        }
+
+        private void showWithActivity(final Activity activity, final int index, boolean useAnim) {
+            final Window window = activity.getWindow();
+            if (window != null) {
+                final ViewGroup decorView = (ViewGroup) window.getDecorView();
+                FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT
+                );
+                lp.gravity = mToast.getGravity();
+                lp.bottomMargin = mToast.getYOffset() + UtilsBridge.getNavBarHeight();
+                lp.leftMargin = mToast.getXOffset();
+                View toastViewSnapshot = getToastViewSnapshot(index);
+                if (useAnim) {
+                    toastViewSnapshot.setAlpha(0);
+                    toastViewSnapshot.animate().alpha(1).setDuration(200).start();
                 }
+                decorView.addView(toastViewSnapshot, lp);
             }
         }
 
-        @Override
-        public View getView() {
-            return mToastView;
+        private View getToastViewSnapshot(final int index) {
+            Bitmap bitmap = UtilsBridge.view2Bitmap(mToastView);
+            ImageView toastIv = new ImageView(Utils.getApp());
+            toastIv.setTag(TAG_TOAST + index);
+            toastIv.setImageBitmap(bitmap);
+            return toastIv;
         }
 
-        @Override
-        public void setDuration(int duration) {
-            mToast.setDuration(duration);
+        private void registerLifecycleCallback() {
+            final int index = sShowingIndex;
+            mActivityLifecycleCallbacks = new Utils.ActivityLifecycleCallbacks() {
+                @Override
+                public void onActivityCreated(@NonNull Activity activity) {
+                    if (isShowing()) {
+                        showWithActivity(activity, index, false);
+                    }
+                }
+            };
+            UtilsBridge.addActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
         }
 
-        @Override
-        public void setGravity(int gravity, int xOffset, int yOffset) {
-            mToast.setGravity(gravity, xOffset, yOffset);
+        private void unregisterLifecycleCallback() {
+            UtilsBridge.removeActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
+            mActivityLifecycleCallbacks = null;
+        }
+
+        private boolean isShowing() {
+            return mActivityLifecycleCallbacks != null;
+        }
+    }
+
+    static abstract class AbsToast implements IToast {
+
+        protected Toast      mToast;
+        protected ToastUtils mToastUtils;
+        protected View       mToastView;
+
+        AbsToast(ToastUtils toastUtils) {
+            mToast = new Toast(Utils.getApp());
+            mToastUtils = toastUtils;
+
+            if (mToastUtils.mGravity != -1 || mToastUtils.mXOffset != -1 || mToastUtils.mYOffset != -1) {
+                mToast.setGravity(mToastUtils.mGravity, mToastUtils.mXOffset, mToastUtils.mYOffset);
+            }
         }
 
         @Override
-        public void setText(int resId) {
-            mToast.setText(resId);
+        public void setToastView(View view) {
+            mToastView = view;
+            mToast.setView(mToastView);
         }
 
         @Override
-        public void setText(CharSequence s) {
-            mToast.setText(s);
+        public void setToastView(CharSequence text) {
+            View utilsToastView = mToastUtils.tryApplyUtilsToastView(text);
+            if (utilsToastView != null) {
+                setToastView(utilsToastView);
+                return;
+            }
+
+            mToastView = mToast.getView();
+            if (mToastView == null || mToastView.findViewById(android.R.id.message) == null) {
+                setToastView(UtilsBridge.layoutId2View(R.layout.utils_toast_view));
+            }
+
+            TextView messageTv = mToastView.findViewById(android.R.id.message);
+            messageTv.setText(text);
+            if (mToastUtils.mTextColor != COLOR_DEFAULT) {
+                messageTv.setTextColor(mToastUtils.mTextColor);
+            }
+            if (mToastUtils.mTextSize != -1) {
+                messageTv.setTextSize(mToastUtils.mTextSize);
+            }
+            setBg(messageTv);
+        }
+
+        protected void setBg(final TextView msgTv) {
+            if (mToastUtils.mBgResource != -1) {
+                mToastView.setBackgroundResource(mToastUtils.mBgResource);
+                msgTv.setBackgroundColor(Color.TRANSPARENT);
+            } else if (mToastUtils.mBgColor != COLOR_DEFAULT) {
+                Drawable toastBg = mToastView.getBackground();
+                Drawable msgBg = msgTv.getBackground();
+                if (toastBg != null && msgBg != null) {
+                    toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));
+                    msgTv.setBackgroundColor(Color.TRANSPARENT);
+                } else if (toastBg != null) {
+                    toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));
+                } else if (msgBg != null) {
+                    msgBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));
+                } else {
+                    mToastView.setBackgroundColor(mToastUtils.mBgColor);
+                }
+            }
         }
 
         @Override
         @CallSuper
         public void cancel() {
+            if (mToast != null) {
+                mToast.cancel();
+            }
             mToast = null;
             mToastView = null;
         }
@@ -566,22 +804,35 @@ public void cancel() {
 
     interface IToast {
 
-        void show();
+        void setToastView(View view);
 
-        void cancel();
+        void setToastView(CharSequence text);
+
+        void show(int duration);
 
-        void setView(View view);
+        void cancel();
+    }
 
-        void setMsgView(CharSequence text);
+    public static final class UtilsMaxWidthRelativeLayout extends RelativeLayout {
 
-        View getView();
+        private static final int SPACING = UtilsBridge.dp2px(80);
 
-        void setDuration(int duration);
+        public UtilsMaxWidthRelativeLayout(Context context) {
+            super(context);
+        }
 
-        void setGravity(int gravity, int xOffset, int yOffset);
+        public UtilsMaxWidthRelativeLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
 
-        void setText(@StringRes int resId);
+        public UtilsMaxWidthRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+            super(context, attrs, defStyleAttr);
+        }
 
-        void setText(CharSequence s);
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            int widthMaxSpec = MeasureSpec.makeMeasureSpec(UtilsBridge.getAppScreenWidth() - SPACING, MeasureSpec.AT_MOST);
+            super.onMeasure(widthMaxSpec, heightMeasureSpec);
+        }
     }
 }
\ No newline at end of file
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java
index 0123ab96c1..5fa5ae3043 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java
@@ -13,11 +13,11 @@
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * 
@@ -33,9 +33,11 @@ final class UtilsActivityLifecycleImpl implements Application.ActivityLifecycleC
 
     private final LinkedList mActivityList = new LinkedList<>();
 
-    private final List                mStatusListeners               = new ArrayList<>();
+    private final List                mStatusListeners               = new CopyOnWriteArrayList<>();
     private final Map> mActivityLifecycleCallbacksMap = new ConcurrentHashMap<>();
 
+    private static final Activity STUB = new Activity();
+
     private int     mForegroundCount = 0;
     private int     mConfigCount     = 0;
     private boolean mIsBackground    = false;
@@ -62,11 +64,11 @@ Activity getTopActivity() {
 
     List getActivityList() {
         if (!mActivityList.isEmpty()) {
-            return mActivityList;
+            return new LinkedList<>(mActivityList);
         }
         List reflectActivities = getActivitiesByReflect();
         mActivityList.addAll(reflectActivities);
-        return mActivityList;
+        return new LinkedList<>(mActivityList);
     }
 
     void addOnAppStatusChangedListener(final Utils.OnAppStatusChangedListener listener) {
@@ -77,6 +79,10 @@ void removeOnAppStatusChangedListener(final Utils.OnAppStatusChangedListener lis
         mStatusListeners.remove(listener);
     }
 
+    void addActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks listener) {
+        addActivityLifecycleCallbacks(STUB, listener);
+    }
+
     void addActivityLifecycleCallbacks(final Activity activity,
                                        final Utils.ActivityLifecycleCallbacks listener) {
         if (activity == null || listener == null) return;
@@ -88,37 +94,20 @@ public void run() {
         });
     }
 
-    Application getApplicationByReflect() {
-        try {
-            Class activityThreadClass = Class.forName("android.app.ActivityThread");
-            Object thread = getActivityThread();
-            Object app = activityThreadClass.getMethod("getApplication").invoke(thread);
-            if (app == null) {
-                return null;
-            }
-            return (Application) app;
-        } catch (InvocationTargetException e) {
-            e.printStackTrace();
-        } catch (NoSuchMethodException e) {
-            e.printStackTrace();
-        } catch (IllegalAccessException e) {
-            e.printStackTrace();
-        } catch (ClassNotFoundException e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
-
     private void addActivityLifecycleCallbacksInner(final Activity activity,
-                                                    final Utils.ActivityLifecycleCallbacks lifecycleCallbacks) {
-        List callbacks = mActivityLifecycleCallbacksMap.get(activity);
-        if (callbacks == null) {
-            callbacks = new ArrayList<>();
-            mActivityLifecycleCallbacksMap.put(activity, callbacks);
+                                                    final Utils.ActivityLifecycleCallbacks callbacks) {
+        List callbacksList = mActivityLifecycleCallbacksMap.get(activity);
+        if (callbacksList == null) {
+            callbacksList = new CopyOnWriteArrayList<>();
+            mActivityLifecycleCallbacksMap.put(activity, callbacksList);
         } else {
-            if (callbacks.contains(lifecycleCallbacks)) return;
+            if (callbacksList.contains(callbacks)) return;
         }
-        callbacks.add(lifecycleCallbacks);
+        callbacksList.add(callbacks);
+    }
+
+    void removeActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) {
+        removeActivityLifecycleCallbacks(STUB, callbacks);
     }
 
     void removeActivityLifecycleCallbacks(final Activity activity) {
@@ -143,36 +132,60 @@ public void run() {
     }
 
     private void removeActivityLifecycleCallbacksInner(final Activity activity,
-                                                       final Utils.ActivityLifecycleCallbacks lifecycleCallbacks) {
-        List callbacks = mActivityLifecycleCallbacksMap.get(activity);
-        if (callbacks != null && !callbacks.isEmpty()) {
-            callbacks.remove(lifecycleCallbacks);
+                                                       final Utils.ActivityLifecycleCallbacks callbacks) {
+        List callbacksList = mActivityLifecycleCallbacksMap.get(activity);
+        if (callbacksList != null && !callbacksList.isEmpty()) {
+            callbacksList.remove(callbacks);
         }
     }
 
     private void consumeActivityLifecycleCallbacks(Activity activity, Lifecycle.Event event) {
-        List listeners = mActivityLifecycleCallbacksMap.get(activity);
-        if (listeners != null) {
-            for (Utils.ActivityLifecycleCallbacks listener : listeners) {
-                listener.onLifecycleChanged(activity, event);
-                if (event.equals(Lifecycle.Event.ON_CREATE)) {
-                    listener.onActivityCreated(activity);
-                } else if (event.equals(Lifecycle.Event.ON_START)) {
-                    listener.onActivityStarted(activity);
-                } else if (event.equals(Lifecycle.Event.ON_RESUME)) {
-                    listener.onActivityResumed(activity);
-                } else if (event.equals(Lifecycle.Event.ON_PAUSE)) {
-                    listener.onActivityPaused(activity);
-                } else if (event.equals(Lifecycle.Event.ON_STOP)) {
-                    listener.onActivityStopped(activity);
-                } else if (event.equals(Lifecycle.Event.ON_DESTROY)) {
-                    listener.onActivityDestroyed(activity);
-                }
+        consumeLifecycle(activity, event, mActivityLifecycleCallbacksMap.get(activity));
+        consumeLifecycle(activity, event, mActivityLifecycleCallbacksMap.get(STUB));
+    }
+
+    private void consumeLifecycle(Activity activity, Lifecycle.Event event, List listeners) {
+        if (listeners == null) return;
+        for (Utils.ActivityLifecycleCallbacks listener : listeners) {
+            listener.onLifecycleChanged(activity, event);
+            if (event.equals(Lifecycle.Event.ON_CREATE)) {
+                listener.onActivityCreated(activity);
+            } else if (event.equals(Lifecycle.Event.ON_START)) {
+                listener.onActivityStarted(activity);
+            } else if (event.equals(Lifecycle.Event.ON_RESUME)) {
+                listener.onActivityResumed(activity);
+            } else if (event.equals(Lifecycle.Event.ON_PAUSE)) {
+                listener.onActivityPaused(activity);
+            } else if (event.equals(Lifecycle.Event.ON_STOP)) {
+                listener.onActivityStopped(activity);
+            } else if (event.equals(Lifecycle.Event.ON_DESTROY)) {
+                listener.onActivityDestroyed(activity);
             }
-            if (event.equals(Lifecycle.Event.ON_DESTROY)) {
-                mActivityLifecycleCallbacksMap.remove(activity);
+        }
+        if (event.equals(Lifecycle.Event.ON_DESTROY)) {
+            mActivityLifecycleCallbacksMap.remove(activity);
+        }
+    }
+
+    Application getApplicationByReflect() {
+        try {
+            Class activityThreadClass = Class.forName("android.app.ActivityThread");
+            Object thread = getActivityThread();
+            Object app = activityThreadClass.getMethod("getApplication").invoke(thread);
+            if (app == null) {
+                return null;
             }
+            return (Application) app;
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
         }
+        return null;
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -180,7 +193,7 @@ private void consumeActivityLifecycleCallbacks(Activity activity, Lifecycle.Even
     ///////////////////////////////////////////////////////////////////////////
     @Override
     public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
-        UtilsBridge.applyLanguage(activity);
+        LanguageUtils.applyLanguage(activity);
         setAnimatorsEnabled();
         setTopActivity(activity);
         consumeActivityLifecycleCallbacks(activity, Lifecycle.Event.ON_CREATE);
@@ -249,23 +262,30 @@ public void onActivityDestroyed(@NonNull Activity activity) {
      * the keyboard from closing when curActivity onDestroy.
      */
     private void processHideSoftInputOnActivityDestroy(final Activity activity, boolean isSave) {
-        if (isSave) {
-            final WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
-            final int softInputMode = attrs.softInputMode;
-            activity.getWindow().getDecorView().setTag(-123, softInputMode);
-            activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
-        } else {
-            final Object tag = activity.getWindow().getDecorView().getTag(-123);
-            if (!(tag instanceof Integer)) return;
-            UtilsBridge.runOnUiThreadDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    Window window = activity.getWindow();
-                    if (window != null) {
-                        window.setSoftInputMode(((Integer) tag));
+        try {
+            if (isSave) {
+                Window window = activity.getWindow();
+                final WindowManager.LayoutParams attrs = window.getAttributes();
+                final int softInputMode = attrs.softInputMode;
+                window.getDecorView().setTag(-123, softInputMode);
+                window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+            } else {
+                final Object tag = activity.getWindow().getDecorView().getTag(-123);
+                if (!(tag instanceof Integer)) return;
+                UtilsBridge.runOnUiThreadDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            Window window = activity.getWindow();
+                            if (window != null) {
+                                window.setSoftInputMode(((Integer) tag));
+                            }
+                        } catch (Exception ignore) {
+                        }
                     }
-                }
-            }, 100);
+                }, 100);
+            }
+        } catch (Exception ignore) {
         }
     }
 
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java
index 97ec53579d..4c36704595 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java
@@ -9,9 +9,12 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Parcelable;
+import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RequiresPermission;
+import android.support.annotation.StringRes;
+import android.text.TextUtils;
 import android.view.View;
 
 import com.google.gson.Gson;
@@ -24,7 +27,9 @@
 import java.io.InputStream;
 import java.io.Serializable;
 import java.lang.reflect.Type;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 import static android.Manifest.permission.CALL_PHONE;
 
@@ -65,6 +70,14 @@ static void removeOnAppStatusChangedListener(final Utils.OnAppStatusChangedListe
         UtilsActivityLifecycleImpl.INSTANCE.removeOnAppStatusChangedListener(listener);
     }
 
+    static void addActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) {
+        UtilsActivityLifecycleImpl.INSTANCE.addActivityLifecycleCallbacks(callbacks);
+    }
+
+    static void removeActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) {
+        UtilsActivityLifecycleImpl.INSTANCE.removeActivityLifecycleCallbacks(callbacks);
+    }
+
     static void addActivityLifecycleCallbacks(final Activity activity,
                                               final Utils.ActivityLifecycleCallbacks callbacks) {
         UtilsActivityLifecycleImpl.INSTANCE.addActivityLifecycleCallbacks(activity, callbacks);
@@ -94,10 +107,6 @@ static boolean isActivityAlive(final Activity activity) {
         return ActivityUtils.isActivityAlive(activity);
     }
 
-    static String getLauncherActivity() {
-        return ActivityUtils.getLauncherActivity();
-    }
-
     static String getLauncherActivity(final String pkg) {
         return ActivityUtils.getLauncherActivity(pkg);
     }
@@ -126,6 +135,10 @@ static Context getTopActivityOrApp() {
         }
     }
 
+    static boolean isAppForeground() {
+        return AppUtils.isAppForeground();
+    }
+
     static boolean isAppRunning(@NonNull final String pkgName) {
         return AppUtils.isAppRunning(pkgName);
     }
@@ -134,18 +147,14 @@ static boolean isAppInstalled(final String pkgName) {
         return AppUtils.isAppInstalled(pkgName);
     }
 
-    static String getAppVersionName() {
-        return AppUtils.getAppVersionName();
-    }
-
-    static int getAppVersionCode() {
-        return AppUtils.getAppVersionCode();
-    }
-
     static boolean isAppDebug() {
         return AppUtils.isAppDebug();
     }
 
+    static void relaunchApp() {
+        AppUtils.relaunchApp();
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // BarUtils
     ///////////////////////////////////////////////////////////////////////////
@@ -418,13 +427,6 @@ static void fixSoftInputLeaks(final Activity activity) {
         KeyboardUtils.fixSoftInputLeaks(activity);
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // LanguageUtils
-    ///////////////////////////////////////////////////////////////////////////
-    static void applyLanguage(final Activity activity) {
-        LanguageUtils.applyLanguage(activity);
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // PermissionUtils
     ///////////////////////////////////////////////////////////////////////////
@@ -460,12 +462,15 @@ static boolean isSamsung() {
     }
 
     ///////////////////////////////////////////////////////////////////////////
-    // SDCardUtils
+    // ScreenUtils
     ///////////////////////////////////////////////////////////////////////////
-    static String getSDCardPathByEnvironment() {
-        return SDCardUtils.getSDCardPathByEnvironment();
+    static int getAppScreenWidth() {
+        return ScreenUtils.getAppScreenWidth();
     }
 
+    ///////////////////////////////////////////////////////////////////////////
+    // SDCardUtils
+    ///////////////////////////////////////////////////////////////////////////
     static boolean isSDCardEnableByEnvironment() {
         return SDCardUtils.isSDCardEnableByEnvironment();
     }
@@ -521,6 +526,18 @@ static boolean equals(final CharSequence s1, final CharSequence s2) {
         return StringUtils.equals(s1, s2);
     }
 
+    static String getString(@StringRes int id) {
+        return StringUtils.getString(id);
+    }
+
+    static String getString(@StringRes int id, Object... formatArgs) {
+        return StringUtils.getString(id, formatArgs);
+    }
+
+    static String format(String str, Object... args) {
+        return StringUtils.format(str, args);
+    }
+
 
     ///////////////////////////////////////////////////////////////////////////
     // ThreadUtils
@@ -579,4 +596,88 @@ static Uri file2Uri(final File file) {
     static File uri2File(final Uri uri) {
         return UriUtils.uri2File(uri);
     }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // ViewUtils
+    ///////////////////////////////////////////////////////////////////////////
+    static View layoutId2View(@LayoutRes final int layoutId) {
+        return ViewUtils.layoutId2View(layoutId);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Common
+    ///////////////////////////////////////////////////////////////////////////
+    static final class FileHead {
+
+        private String                        mName;
+        private LinkedHashMap mFirst = new LinkedHashMap<>();
+        private LinkedHashMap mLast  = new LinkedHashMap<>();
+
+        FileHead(String name) {
+            mName = name;
+        }
+
+        void addFirst(String key, String value) {
+            append2Host(mFirst, key, value);
+        }
+
+        void append(Map extra) {
+            append2Host(mLast, extra);
+        }
+
+        void append(String key, String value) {
+            append2Host(mLast, key, value);
+        }
+
+        private void append2Host(Map host, Map extra) {
+            if (extra == null || extra.isEmpty()) {
+                return;
+            }
+            for (Map.Entry entry : extra.entrySet()) {
+                append2Host(host, entry.getKey(), entry.getValue());
+            }
+        }
+
+        private void append2Host(Map host, String key, String value) {
+            if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
+                return;
+            }
+            int delta = 19 - key.length(); // 19 is length of "Device Manufacturer"
+            if (delta > 0) {
+                key = key + "                   ".substring(0, delta);
+            }
+            host.put(key, value);
+        }
+
+        public String getAppended() {
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry entry : mLast.entrySet()) {
+                sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            String border = "************* " + mName + " Head ****************\n";
+            sb.append(border);
+            for (Map.Entry entry : mFirst.entrySet()) {
+                sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
+            }
+
+            sb.append("Rom Info           : ").append(RomUtils.getRomInfo()).append("\n");
+            sb.append("Device Manufacturer: ").append(Build.MANUFACTURER).append("\n");
+            sb.append("Device Model       : ").append(Build.MODEL).append("\n");
+            sb.append("Android Version    : ").append(Build.VERSION.RELEASE).append("\n");
+            sb.append("Android SDK        : ").append(Build.VERSION.SDK_INT).append("\n");
+            sb.append("App VersionName    : ").append(AppUtils.getAppVersionName()).append("\n");
+            sb.append("App VersionCode    : ").append(AppUtils.getAppVersionCode()).append("\n");
+
+            sb.append(getAppended());
+            return sb.append(border).append("\n").toString();
+        }
+    }
 }
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsTransActivity.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsTransActivity.java
index 1b87d3687f..1d6e1dc7e0 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsTransActivity.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsTransActivity.java
@@ -131,7 +131,7 @@ protected void onDestroy() {
     }
 
     @Override
-    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         TransActivityDelegate callback = CALLBACK_MAP.get(this);
         if (callback == null) return;
@@ -173,7 +173,7 @@ public void onStopped(@NonNull UtilsTransActivity activity) {/**/}
 
         public void onSaveInstanceState(@NonNull UtilsTransActivity activity, Bundle outState) {/**/}
 
-        public void onRequestPermissionsResult(@NonNull UtilsTransActivity activity, int requestCode, String[] permissions, int[] grantResults) {/**/}
+        public void onRequestPermissionsResult(@NonNull UtilsTransActivity activity, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {/**/}
 
         public void onActivityResult(@NonNull UtilsTransActivity activity, int requestCode, int resultCode, Intent data) {/**/}
 
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java
index 44ef6dc2cf..a06e3503bf 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java
@@ -1,7 +1,10 @@
 package com.blankj.utilcode.util;
 
+import android.content.Context;
 import android.os.Build;
+import android.support.annotation.LayoutRes;
 import android.text.TextUtils;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -106,4 +109,10 @@ public static void fixScrollViewTopping(View view) {
             }
         }
     }
+
+    public static View layoutId2View(@LayoutRes final int layoutId) {
+        LayoutInflater inflate =
+                (LayoutInflater) Utils.getApp().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        return inflate.inflate(layoutId, null);
+    }
 }
\ No newline at end of file
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/VolumeUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/VolumeUtils.java
new file mode 100644
index 0000000000..ed3b62ae76
--- /dev/null
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/VolumeUtils.java
@@ -0,0 +1,120 @@
+package com.blankj.utilcode.util;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Build;
+
+/**
+ * 
+ *     author: blankj
+ *     blog  : http://blankj.com
+ *     time  : 2020/09/08
+ *     desc  : utils about volume
+ * 
+ */ +public class VolumeUtils { + + /** + * Return the volume. + * + * @param streamType The stream type. + *
    + *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • + *
  • {@link AudioManager#STREAM_SYSTEM}
  • + *
  • {@link AudioManager#STREAM_RING}
  • + *
  • {@link AudioManager#STREAM_MUSIC}
  • + *
  • {@link AudioManager#STREAM_ALARM}
  • + *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • + *
  • {@link AudioManager#STREAM_DTMF}
  • + *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • + *
+ * @return the volume + */ + public static int getVolume(int streamType) { + AudioManager am = (AudioManager) Utils.getApp().getSystemService(Context.AUDIO_SERVICE); + //noinspection ConstantConditions + return am.getStreamVolume(streamType); + } + + /** + * Sets media volume.
+ * When setting the value of parameter 'volume' greater than the maximum value of the media volume will not either cause error or throw exception but maximize the media volume.
+ * Setting the value of volume lower than 0 will minimize the media volume. + * + * @param streamType The stream type. + *
    + *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • + *
  • {@link AudioManager#STREAM_SYSTEM}
  • + *
  • {@link AudioManager#STREAM_RING}
  • + *
  • {@link AudioManager#STREAM_MUSIC}
  • + *
  • {@link AudioManager#STREAM_ALARM}
  • + *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • + *
  • {@link AudioManager#STREAM_DTMF}
  • + *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • + *
+ * @param volume The volume. + * @param flags The flags. + *
    + *
  • {@link AudioManager#FLAG_SHOW_UI}
  • + *
  • {@link AudioManager#FLAG_ALLOW_RINGER_MODES}
  • + *
  • {@link AudioManager#FLAG_PLAY_SOUND}
  • + *
  • {@link AudioManager#FLAG_REMOVE_SOUND_AND_VIBRATE}
  • + *
  • {@link AudioManager#FLAG_VIBRATE}
  • + *
+ */ + public static void setVolume(int streamType, int volume, int flags) { + AudioManager am = (AudioManager) Utils.getApp().getSystemService(Context.AUDIO_SERVICE); + try { + //noinspection ConstantConditions + am.setStreamVolume(streamType, volume, flags); + } catch (SecurityException ignore) { + } + } + + /** + * Return the maximum volume. + * + * @param streamType The stream type. + *
    + *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • + *
  • {@link AudioManager#STREAM_SYSTEM}
  • + *
  • {@link AudioManager#STREAM_RING}
  • + *
  • {@link AudioManager#STREAM_MUSIC}
  • + *
  • {@link AudioManager#STREAM_ALARM}
  • + *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • + *
  • {@link AudioManager#STREAM_DTMF}
  • + *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • + *
+ * @return the maximum volume + */ + public static int getMaxVolume(int streamType) { + AudioManager am = (AudioManager) Utils.getApp().getSystemService(Context.AUDIO_SERVICE); + //noinspection ConstantConditions + return am.getStreamMaxVolume(streamType); + } + + /** + * Return the minimum volume. + * + * @param streamType The stream type. + *
    + *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • + *
  • {@link AudioManager#STREAM_SYSTEM}
  • + *
  • {@link AudioManager#STREAM_RING}
  • + *
  • {@link AudioManager#STREAM_MUSIC}
  • + *
  • {@link AudioManager#STREAM_ALARM}
  • + *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • + *
  • {@link AudioManager#STREAM_DTMF}
  • + *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • + *
+ * @return the minimum volume + */ + public static int getMinVolume(int streamType) { + AudioManager am = (AudioManager) Utils.getApp().getSystemService(Context.AUDIO_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + //noinspection ConstantConditions + return am.getStreamMinVolume(streamType); + } + return 0; + } +} diff --git a/lib/utilcode/src/main/res/drawable/toast_frame.xml b/lib/utilcode/src/main/res/drawable/utils_toast_bg.xml similarity index 79% rename from lib/utilcode/src/main/res/drawable/toast_frame.xml rename to lib/utilcode/src/main/res/drawable/utils_toast_bg.xml index 24e3922412..5e6370b319 100644 --- a/lib/utilcode/src/main/res/drawable/toast_frame.xml +++ b/lib/utilcode/src/main/res/drawable/utils_toast_bg.xml @@ -1,7 +1,6 @@ - diff --git a/lib/utilcode/src/main/res/layout/toast_layout.xml b/lib/utilcode/src/main/res/layout/toast_layout.xml deleted file mode 100644 index d66836ea8f..0000000000 --- a/lib/utilcode/src/main/res/layout/toast_layout.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - \ No newline at end of file diff --git a/lib/utilcode/src/main/res/layout/utils_toast_view.xml b/lib/utilcode/src/main/res/layout/utils_toast_view.xml new file mode 100644 index 0000000000..59af74b6bb --- /dev/null +++ b/lib/utilcode/src/main/res/layout/utils_toast_view.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/utildebug/src/main/java/com/blankj/utildebug/DebugUtils.java b/lib/utildebug/src/main/java/com/blankj/utildebug/DebugUtils.java index 4a5d48fb8b..9855aa9b57 100644 --- a/lib/utildebug/src/main/java/com/blankj/utildebug/DebugUtils.java +++ b/lib/utildebug/src/main/java/com/blankj/utildebug/DebugUtils.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.support.annotation.DrawableRes; import android.view.ViewGroup; +import android.view.ViewParent; import com.blankj.utilcode.util.Utils; import com.blankj.utildebug.debug.IDebug; @@ -71,6 +72,10 @@ public void onActivityStarted(Activity activity) { @Override public void onActivityResumed(Activity activity) { + ViewParent parent = DebugIcon.getInstance().getParent(); + if (parent != null) { + ((ViewGroup) parent).removeView(DebugIcon.getInstance()); + } ((ViewGroup) activity.findViewById(android.R.id.content)).addView(DebugIcon.getInstance(), mParams); } diff --git a/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/SwipeRightMenu.java b/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/SwipeRightMenu.java index 39ff5d7ada..2ab3325121 100644 --- a/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/SwipeRightMenu.java +++ b/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/SwipeRightMenu.java @@ -167,7 +167,7 @@ public boolean dispatchTouchEvent(MotionEvent event) { if (isOpen()) { if (isTouchPointInView(mContentView, x, y)) { close(true); - final long now = SystemClock.uptimeMillis(); + final long now = SystemClock.elapsedRealtime(); final MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); super.dispatchTouchEvent(cancelEvent); @@ -292,7 +292,7 @@ public void close(SwipeRightMenu exclude) { } private void cancelChildViewTouch() { - final long now = SystemClock.uptimeMillis(); + final long now = SystemClock.elapsedRealtime(); final MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); final int childCount = getChildCount(); From c351507a082875429db451bef2a818aead420077 Mon Sep 17 00:00:00 2001 From: Blankj Date: Sun, 25 Oct 2020 02:53:58 +0800 Subject: [PATCH 15/61] see 10/25 log --- .../com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java | 2 -- lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java | 7 ++++--- lib/base/src/main/java/com/blankj/base/mvp/BaseView.java | 2 ++ .../java/com/blankj/utilcode/util/DebouncingUtils.java | 3 ++- .../src/main/java/com/blankj/utilcode/util/ViewUtils.java | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java index 05ae20c92d..7fff29f4a7 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java @@ -1,7 +1,5 @@ package com.blankj.utilcode.pkg.feature.mvp; -import android.arch.lifecycle.ViewModel; -import android.arch.lifecycle.ViewModelProvider; import android.content.Context; import android.content.Intent; import android.os.Bundle; 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 84c930fd74..2f2b81d6e0 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,11 @@ package com.blankj.base.mvp; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.support.annotation.CallSuper; import android.util.Log; +import androidx.annotation.CallSuper; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + /** *
  *     author: blankj
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 94f36bcdaa..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
@@ -5,10 +5,12 @@
 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;
 
 /**
  * 
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
index c9f2c8ff79..889ac86090 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java
@@ -1,7 +1,6 @@
 package com.blankj.utilcode.util;
 
 import android.os.SystemClock;
-import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.view.View;
 
@@ -9,6 +8,8 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import androidx.annotation.NonNull;
+
 /**
  * 
  *     author: Blankj
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java
index a06e3503bf..f0ef043322 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ViewUtils.java
@@ -2,7 +2,6 @@
 
 import android.content.Context;
 import android.os.Build;
-import android.support.annotation.LayoutRes;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -10,6 +9,8 @@
 
 import java.util.Locale;
 
+import androidx.annotation.LayoutRes;
+
 /**
  * 
  *     author: Blankj

From d1ff4e3cd680473dc63b491a9795bd790a464949 Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Sun, 25 Oct 2020 03:52:23 +0800
Subject: [PATCH 16/61] see 10/25 log

---
 lib/utilcode/build.gradle | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/utilcode/build.gradle b/lib/utilcode/build.gradle
index dd2df94746..283e55936b 100644
--- a/lib/utilcode/build.gradle
+++ b/lib/utilcode/build.gradle
@@ -40,6 +40,10 @@ dependencies {
     testImplementation Config.depConfig.eventbus_lib.dep
 }
 
+afterEvaluate {
+    verifyReleaseResources.enabled(false)
+}
+
 apply from: "${rootDir.path}/gradle/publish.gradle"
 publish {
     name = "UtilCode"

From c7f9b2df4ef9a3d1a240464600a7e691b2f9ae68 Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Mon, 26 Oct 2020 01:28:55 +0800
Subject: [PATCH 17/61] see 10/26 log

---
 README-CN.md                                    |   4 +---
 README.md                                       |   4 +---
 art/wechat.png                                  | Bin 72567 -> 0 bytes
 .../plugin/readme/ReadmeCorePlugin.groovy       |   2 +-
 lib/utilcode/README-CN.md                       |   4 +---
 lib/utilcode/README.md                          |   1 -
 .../com/blankj/utilcode/util/ToastUtils.java    |   2 +-
 7 files changed, 5 insertions(+), 12 deletions(-)
 delete mode 100644 art/wechat.png

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://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/wechat.png)
+欢迎加入我的小专栏「**[基你太美](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://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/wechat.png)
+欢迎加入我的小专栏「**[基你太美](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 e166a4783fdc3f25c63ec2417f8717dc74bdfcec..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 72567
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

+fm0 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 { } } else if (line.contains(": ") && !line.contains("[")) { sb.append(line.substring(0, line.indexOf(':')).trim()) - } else if (line.contains("打个小广告") || line.contains("知识星球") || line.contains("我的二维码")) { + } else if (line.contains("打个小广告") || line.contains("基你太美")) { return } else { sb.append(line) diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index 45928eec20..865e218900 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -1253,9 +1253,7 @@ getComments : 获取压缩文件中的注释链表 ## 打个小广告 -欢迎加入我的知识星球「**[基你太美](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://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/wechat.png) +欢迎加入我的小专栏「**[基你太美](https://xiaozhuanlan.com/Blankj)**」一起学习。 diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index 27bb7c4990..11415c7899 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -1255,7 +1255,6 @@ getComments - [activity.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/ActivityUtils.java [activity.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java index 0bdd221a29..908ad08691 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java @@ -477,7 +477,7 @@ private static IToast newToast(ToastUtils toastUtils) { } } - // no notification + // not use system or notification disable if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_TOAST); } else if (UtilsBridge.isGrantedDrawOverlays()) { From a509f949f908c789eee2ce02cd098380881877fd Mon Sep 17 00:00:00 2001 From: Blankj Date: Mon, 26 Oct 2020 14:50:52 +0800 Subject: [PATCH 18/61] see 10/26 log --- CHANGELOG.md | 1 + buildSrc/src/main/groovy/Config.groovy | 4 +- .../utilcode/pkg/feature/app/AppActivity.kt | 33 +++++++++++--- lib/utilcode/README-CN.md | 5 ++- lib/utilcode/README.md | 5 ++- .../constant/PermissionConstants.java | 2 +- .../blankj/utilcode/util/ActivityUtils.java | 45 +++++++++++-------- .../com/blankj/utilcode/util/AppUtils.java | 13 +----- .../blankj/utilcode/util/DebouncingUtils.java | 2 +- .../com/blankj/utilcode/util/ToastUtils.java | 35 +++++++++------ .../util/UtilsActivityLifecycleImpl.java | 4 ++ .../com/blankj/utilcode/util/UtilsBridge.java | 17 ++----- 12 files changed, 97 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f418e68ab7..52098557b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* `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. diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index d292b40954..b193347c12 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -14,8 +14,8 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_000 - static versionName = '1.30.0'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_001 + static versionName = '1.30.1'// E.g. 1.9.72 => 1,009,072 // lib version static gradlePluginVersion = '3.5.0' diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt index 7e6f10785a..5499f78eb7 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt @@ -1,13 +1,11 @@ package com.blankj.utilcode.pkg.feature.app +import android.app.Activity import android.content.Context import android.content.Intent import com.blankj.common.activity.CommonActivity import com.blankj.common.helper.PermissionHelper -import com.blankj.common.item.CommonItem -import com.blankj.common.item.CommonItemClick -import com.blankj.common.item.CommonItemImage -import com.blankj.common.item.CommonItemTitle +import com.blankj.common.item.* import com.blankj.utilcode.constant.PermissionConstants import com.blankj.utilcode.pkg.Config import com.blankj.utilcode.pkg.R @@ -21,7 +19,9 @@ import com.blankj.utilcode.util.* * desc : demo about AppUtils * ``` */ -class AppActivity : CommonActivity() { +class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener { + + var isRegisterAppStatusChangedListener: Boolean = false companion object { fun start(context: Context) { @@ -54,6 +54,14 @@ class AppActivity : CommonActivity() { override fun bindItems(): MutableList> { return CollectionUtils.newArrayList( + CommonItemSwitch("registerAppStatusChangedListener", { isRegisterAppStatusChangedListener }, { + isRegisterAppStatusChangedListener = it + if (it) { + AppUtils.registerAppStatusChangedListener(this) + } else { + AppUtils.unregisterAppStatusChangedListener(this) + } + }), CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()), CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()), CommonItemTitle("isAppSystem", AppUtils.isAppSystem().toString()), @@ -105,6 +113,21 @@ class AppActivity : CommonActivity() { } ) } + + override fun onForeground(activity: Activity) { + ToastUtils.showShort("onForeground\n${activity.javaClass.simpleName}") + } + + override fun onBackground(activity: Activity) { + ToastUtils.showShort("onBackground\n${activity.javaClass.simpleName}") + } + + override fun onDestroy() { + super.onDestroy() + if (isRegisterAppStatusChangedListener) { + AppUtils.unregisterAppStatusChangedListener(this) + } + } } class ReleaseInstallApkTask(private val mListener: OnReleasedListener) : ThreadUtils.SimpleTask() { diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index 865e218900..1a1f671eb6 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.0' +implementation 'com.blankj:utilcode:1.30.1' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.0' +implementation 'com.blankj:utilcodex:1.30.1' ``` @@ -1181,6 +1181,7 @@ make.setRightIcon : 设置右侧图标 make.setBottomIcon : 设置底部图标 make.setNotUseSystemToast: 设置不使用系统吐司 make.show : 显示吐司 +getDefaultMaker : 获取默认制作实例(控制 showShort、showLong 样式) showShort : 显示短时吐司 showLong : 显示长时吐司 cancel : 取消吐司显示 diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index 11415c7899..cbb2d1f797 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.0' +implementation 'com.blankj:utilcode:1.30.1' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.0' +implementation 'com.blankj:utilcodex:1.30.1' ``` @@ -1181,6 +1181,7 @@ make.setRightIcon make.setBottomIcon make.setNotUseSystemToast make.show +getDefaultMaker showShort showLong cancel diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java index 671b654bd9..e42111beaa 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/PermissionConstants.java @@ -41,7 +41,7 @@ public final class PermissionConstants { permission.READ_CONTACTS, permission.WRITE_CONTACTS, permission.GET_ACCOUNTS }; private static final String[] GROUP_LOCATION = { - permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION + permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION, permission.ACCESS_BACKGROUND_LOCATION }; private static final String[] GROUP_MICROPHONE = { permission.RECORD_AUDIO 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 c4c2e0a8a5..5a185d47a1 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 @@ -159,7 +159,7 @@ public static boolean isActivityExists(@NonNull final String pkg, * @param clz The activity class. */ public static void startActivity(@NonNull final Class clz) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, null, context.getPackageName(), clz.getName(), null); } @@ -171,7 +171,7 @@ public static void startActivity(@NonNull final Class clz) { */ public static void startActivity(@NonNull final Class clz, @Nullable final Bundle options) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, null, context.getPackageName(), clz.getName(), options); } @@ -187,7 +187,7 @@ public static void startActivity(@NonNull final Class clz, public static void startActivity(@NonNull final Class 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) { @@ -263,7 +263,7 @@ public static void startActivity(@NonNull final Activity activity, */ public static void startActivity(@NonNull final Bundle extras, @NonNull final Class clz) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, extras, context.getPackageName(), clz.getName(), null); } @@ -277,7 +277,7 @@ public static void startActivity(@NonNull final Bundle extras, public static void startActivity(@NonNull final Bundle extras, @NonNull final Class clz, @Nullable final Bundle options) { - Context context = UtilsBridge.getTopActivityOrApp(); + Context context = getTopActivityOrApp(); startActivity(context, extras, context.getPackageName(), clz.getName(), options); } @@ -295,7 +295,7 @@ public static void startActivity(@NonNull final Bundle extras, @NonNull final Class 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) { @@ -379,7 +379,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); } /** @@ -392,7 +392,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); } /** @@ -409,7 +409,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); @@ -492,7 +492,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); } /** @@ -507,7 +507,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); } /** @@ -526,7 +526,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); @@ -613,7 +613,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); } /** @@ -625,7 +625,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); } /** @@ -641,7 +641,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) { @@ -1333,7 +1333,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); } /** @@ -1344,7 +1344,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); } /** @@ -1359,7 +1359,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); @@ -2117,4 +2117,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/AppUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/AppUtils.java index 9ba8830644..f68508f3b4 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 @@ -179,18 +179,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; - List info = 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(); } /** 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 index c9f2c8ff79..e6c3c54208 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java @@ -17,7 +17,7 @@ * desc : utils about debouncing *

*/ -class DebouncingUtils { +public class DebouncingUtils { private static final int CACHE_SIZE = 64; private static final Map KEY_MILLIS_MAP = new ConcurrentHashMap<>(CACHE_SIZE); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java index 908ad08691..69bce2594b 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java @@ -57,11 +57,11 @@ public final class ToastUtils { String DARK = "dark"; } - private static final String TAG_TOAST = "TAG_TOAST"; - private static final int COLOR_DEFAULT = 0xFEFFFFFF; - private static final String NULL = "toast null"; - private static final String NOTHING = "toast nothing"; - private static final ToastUtils DEFAULT_TOAST_UTILS = make(); + private static final String TAG_TOAST = "TAG_TOAST"; + private static final int COLOR_DEFAULT = 0xFEFFFFFF; + private static final String NULL = "toast null"; + private static final String NOTHING = "toast nothing"; + private static final ToastUtils DEFAULT_MAKER = make(); private static IToast iToast; @@ -258,6 +258,15 @@ public final ToastUtils setNotUseSystemToast() { return this; } + /** + * Return the default {@link ToastUtils} instance. + * + * @return the default {@link ToastUtils} instance + */ + public static ToastUtils getDefaultMaker() { + return DEFAULT_MAKER; + } + /** * Show the toast for a short period of time. * @@ -351,7 +360,7 @@ private View tryApplyUtilsToastView(final CharSequence text) { * @param text The text. */ public static void showShort(final CharSequence text) { - show(text, Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS); + show(text, Toast.LENGTH_SHORT, DEFAULT_MAKER); } /** @@ -360,7 +369,7 @@ public static void showShort(final CharSequence text) { * @param resId The resource id for text. */ public static void showShort(@StringRes final int resId) { - show(UtilsBridge.getString(resId), Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS); + show(UtilsBridge.getString(resId), Toast.LENGTH_SHORT, DEFAULT_MAKER); } /** @@ -370,7 +379,7 @@ public static void showShort(@StringRes final int resId) { * @param args The args. */ public static void showShort(@StringRes final int resId, final Object... args) { - show(UtilsBridge.getString(resId, args), Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS); + show(UtilsBridge.getString(resId, args), Toast.LENGTH_SHORT, DEFAULT_MAKER); } /** @@ -380,7 +389,7 @@ public static void showShort(@StringRes final int resId, final Object... args) { * @param args The args. */ public static void showShort(final String format, final Object... args) { - show(UtilsBridge.format(format, args), Toast.LENGTH_SHORT, DEFAULT_TOAST_UTILS); + show(UtilsBridge.format(format, args), Toast.LENGTH_SHORT, DEFAULT_MAKER); } /** @@ -389,7 +398,7 @@ public static void showShort(final String format, final Object... args) { * @param text The text. */ public static void showLong(final CharSequence text) { - show(text, Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS); + show(text, Toast.LENGTH_LONG, DEFAULT_MAKER); } /** @@ -398,7 +407,7 @@ public static void showLong(final CharSequence text) { * @param resId The resource id for text. */ public static void showLong(@StringRes final int resId) { - show(UtilsBridge.getString(resId), Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS); + show(UtilsBridge.getString(resId), Toast.LENGTH_LONG, DEFAULT_MAKER); } /** @@ -408,7 +417,7 @@ public static void showLong(@StringRes final int resId) { * @param args The args. */ public static void showLong(@StringRes final int resId, final Object... args) { - show(UtilsBridge.getString(resId), Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS); + show(UtilsBridge.getString(resId), Toast.LENGTH_LONG, DEFAULT_MAKER); } /** @@ -418,7 +427,7 @@ public static void showLong(@StringRes final int resId, final Object... args) { * @param args The args. */ public static void showLong(final String format, final Object... args) { - show(UtilsBridge.format(format, args), Toast.LENGTH_LONG, DEFAULT_TOAST_UTILS); + show(UtilsBridge.format(format, args), Toast.LENGTH_LONG, DEFAULT_MAKER); } /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java index 5fa5ae3043..b3ecdf55b8 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java @@ -94,6 +94,10 @@ public void run() { }); } + boolean isAppForeground() { + return !mIsBackground; + } + private void addActivityLifecycleCallbacksInner(final Activity activity, final Utils.ActivityLifecycleCallbacks callbacks) { List callbacksList = mActivityLifecycleCallbacksMap.get(activity); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java index 4c36704595..86ba24bd89 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java @@ -100,6 +100,10 @@ static Application getApplicationByReflect() { return UtilsActivityLifecycleImpl.INSTANCE.getApplicationByReflect(); } + static boolean isAppForeground() { + return UtilsActivityLifecycleImpl.INSTANCE.isAppForeground(); + } + /////////////////////////////////////////////////////////////////////////// // ActivityUtils /////////////////////////////////////////////////////////////////////////// @@ -126,19 +130,6 @@ static void finishAllActivities() { /////////////////////////////////////////////////////////////////////////// // AppUtils /////////////////////////////////////////////////////////////////////////// - static Context getTopActivityOrApp() { - if (AppUtils.isAppForeground()) { - Activity topActivity = getTopActivity(); - return topActivity == null ? Utils.getApp() : topActivity; - } else { - return Utils.getApp(); - } - } - - static boolean isAppForeground() { - return AppUtils.isAppForeground(); - } - static boolean isAppRunning(@NonNull final String pkgName) { return AppUtils.isAppRunning(pkgName); } From 43e76ff71c824f43b1dd5fb8f8e922b36900329e Mon Sep 17 00:00:00 2001 From: Blankj Date: Tue, 27 Oct 2020 16:43:45 +0800 Subject: [PATCH 19/61] see 10/27 log --- CHANGELOG.md | 1 + buildSrc/src/main/groovy/Config.groovy | 4 +- .../utilcode/pkg/feature/app/AppActivity.kt | 6 +- .../pkg/feature/device/DeviceActivity.kt | 3 + lib/utilcode/README-CN.md | 39 ++++----- lib/utilcode/README.md | 13 +-- .../com/blankj/utilcode/util/AppUtils.java | 85 ++++++++++++------- .../com/blankj/utilcode/util/DeviceUtils.java | 13 +++ .../blankj/utilcode/util/PermissionUtils.java | 2 +- .../blankj/utilcode/util/ObjectUtilsTest.java | 2 + 10 files changed, 106 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52098557b1..2850fa22fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* `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. diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index b193347c12..c707febcbd 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -14,8 +14,8 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_001 - static versionName = '1.30.1'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_002 + static versionName = '1.30.2'// E.g. 1.9.72 => 1,009,072 // lib version static gradlePluginVersion = '3.5.0' diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt index 5499f78eb7..175fa1bc3b 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt @@ -75,9 +75,9 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener { CommonItemTitle("getAppPath", AppUtils.getAppPath()), CommonItemTitle("getAppVersionName", AppUtils.getAppVersionName()), CommonItemTitle("getAppVersionCode", AppUtils.getAppVersionCode().toString()), - CommonItemTitle("getAppSignatureSHA1", AppUtils.getAppSignatureSHA1()), - CommonItemTitle("getAppSignatureSHA256", AppUtils.getAppSignatureSHA256()), - CommonItemTitle("getAppSignatureMD5", AppUtils.getAppSignatureMD5()), + CommonItemTitle("getAppSignaturesSHA1", AppUtils.getAppSignaturesSHA1().toString()), + CommonItemTitle("getAppSignaturesSHA256", AppUtils.getAppSignaturesSHA256().toString()), + CommonItemTitle("getAppSignaturesMD5", AppUtils.getAppSignaturesMD5().toString()), CommonItemTitle("getAppUid", AppUtils.getAppUid().toString()), CommonItemTitle("getApkInfo", AppUtils.getApkInfo(AppUtils.getAppPath()).toString()), diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt index 1df423ded3..d70fe14e93 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt @@ -46,6 +46,9 @@ class DeviceActivity : CommonActivity() { add(CommonItemTitle("getABIs", Arrays.asList(*DeviceUtils.getABIs()).toString())) add(CommonItemTitle("isTablet", DeviceUtils.isTablet().toString())) add(CommonItemTitle("isEmulator", DeviceUtils.isEmulator().toString())) + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { + add(CommonItemTitle("isDevelopmentSettingsEnabled", DeviceUtils.isDevelopmentSettingsEnabled().toString())) + } add(CommonItemTitle("getUniqueDeviceId", DeviceUtils.getUniqueDeviceId("util"))) add(CommonItemTitle("isSameDevice", DeviceUtils.isSameDevice(DeviceUtils.getUniqueDeviceId()).toString())) } diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index 1a1f671eb6..15f6af4970 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.1' +implementation 'com.blankj:utilcode:1.30.2' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.1' +implementation 'com.blankj:utilcodex:1.30.2' ``` @@ -71,10 +71,10 @@ getAppName : 获取 App 名称 getAppPath : 获取 App 路径 getAppVersionName : 获取 App 版本号 getAppVersionCode : 获取 App 版本码 -getAppSignature : 获取 App 签名 -getAppSignatureSHA1 : 获取应用签名的的 SHA1 值 -getAppSignatureSHA256 : 获取应用签名的的 SHA256 值 -getAppSignatureMD5 : 获取应用签名的的 MD5 值 +getAppSignatures : 获取 App 签名 +getAppSignaturesSHA1 : 获取应用签名的的 SHA1 值 +getAppSignaturesSHA256 : 获取应用签名的的 SHA256 值 +getAppSignaturesMD5 : 获取应用签名的的 MD5 值 getAppInfo : 获取 App 信息 getAppsInfo : 获取所有已安装 App 信息 getApkInfo : 获取 Apk 信息 @@ -401,19 +401,20 @@ isValid: 是否有效 * ### 设备相关 -> [DeviceUtils.java][device.java] -> [Demo][device.demo] ``` -isDeviceRooted : 判断设备是否 rooted -isAdbEnabled : 判断设备 ADB 是否可用 -getSDKVersionName: 获取设备系统版本号 -getSDKVersionCode: 获取设备系统版本码 -getAndroidID : 获取设备 AndroidID -getMacAddress : 获取设备 MAC 地址 -getManufacturer : 获取设备厂商 -getModel : 获取设备型号 -getABIs : 获取设备 ABIs -isTablet : 判断是否是平板 -isEmulator : 判断是否是模拟器 -getUniqueDeviceId: 获取唯一设备 ID -isSameDevice : 判断是否同一设备 +isDeviceRooted : 判断设备是否 rooted +isAdbEnabled : 判断设备 ADB 是否可用 +getSDKVersionName : 获取设备系统版本号 +getSDKVersionCode : 获取设备系统版本码 +getAndroidID : 获取设备 AndroidID +getMacAddress : 获取设备 MAC 地址 +getManufacturer : 获取设备厂商 +getModel : 获取设备型号 +getABIs : 获取设备 ABIs +isTablet : 判断是否是平板 +isEmulator : 判断是否是模拟器 +isDevelopmentSettingsEnabled: 开发者选项是否打开 +getUniqueDeviceId : 获取唯一设备 ID +isSameDevice : 判断是否同一设备 ``` * ### 闪光灯相关 -> [FlashlightUtils.java][flashlight.java] -> [Demo][flashlight.demo] diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index cbb2d1f797..f85e0b5fac 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.1' +implementation 'com.blankj:utilcode:1.30.2' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.1' +implementation 'com.blankj:utilcodex:1.30.2' ``` @@ -71,10 +71,10 @@ getAppName getAppPath getAppVersionName getAppVersionCode -getAppSignature -getAppSignatureSHA1 -getAppSignatureSHA256 -getAppSignatureMD5 +getAppSignatures +getAppSignaturesSHA1 +getAppSignaturesSHA256 +getAppSignaturesMD5 getAppInfo getAppsInfo getApkInfo @@ -412,6 +412,7 @@ getModel getABIs isTablet isEmulator +isDevelopmentSettingsEnabled getUniqueDeviceId isSameDevice ``` 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 f68508f3b4..b4884a3442 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 @@ -8,6 +8,7 @@ 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.os.Build; @@ -498,8 +499,8 @@ public static int getAppVersionCode(final String packageName) { * * @return the application's signature */ - public static Signature[] getAppSignature() { - return getAppSignature(Utils.getApp().getPackageName()); + public static Signature[] getAppSignatures() { + return getAppSignatures(Utils.getApp().getPackageName()); } /** @@ -508,17 +509,26 @@ public static Signature[] getAppSignature() { * @param packageName The name of the package. * @return the application's signature */ - public static Signature[] getAppSignature(final String packageName) { + public static Signature[] getAppSignatures(final String packageName) { if (UtilsBridge.isSpace(packageName)) return null; try { PackageManager pm = Utils.getApp().getPackageManager(); - PackageInfo pi; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES); + 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 { - pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + if (pi == null) return null; + + return pi.signatures; } - return pi == null ? null : pi.signatures; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return null; @@ -531,16 +541,25 @@ public static Signature[] getAppSignature(final String packageName) { * @param file The file. * @return the application's signature */ - public static Signature[] getAppSignature(final File file) { + public static Signature[] getAppSignatures(final File file) { if (file == null) return null; PackageManager pm = Utils.getApp().getPackageManager(); - PackageInfo pi; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - pi = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNING_CERTIFICATES); + 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 { - pi = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNATURES); + PackageInfo pi = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNATURES); + if (pi == null) return null; + + return pi.signatures; } - return pi == null ? null : pi.signatures; } /** @@ -548,8 +567,8 @@ public static Signature[] getAppSignature(final File file) { * * @return the application's signature for SHA1 value */ - public static String getAppSignatureSHA1() { - return getAppSignatureSHA1(Utils.getApp().getPackageName()); + public static List getAppSignaturesSHA1() { + return getAppSignaturesSHA1(Utils.getApp().getPackageName()); } /** @@ -558,8 +577,8 @@ 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"); + public static List getAppSignaturesSHA1(final String packageName) { + return getAppSignaturesHash(packageName, "SHA1"); } /** @@ -567,8 +586,8 @@ public static String getAppSignatureSHA1(final String packageName) { * * @return the application's signature for SHA256 value */ - public static String getAppSignatureSHA256() { - return getAppSignatureSHA256(Utils.getApp().getPackageName()); + public static List getAppSignaturesSHA256() { + return getAppSignaturesSHA256(Utils.getApp().getPackageName()); } /** @@ -577,8 +596,8 @@ 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"); + public static List getAppSignaturesSHA256(final String packageName) { + return getAppSignaturesHash(packageName, "SHA256"); } /** @@ -586,8 +605,8 @@ public static String getAppSignatureSHA256(final String packageName) { * * @return the application's signature for MD5 value */ - public static String getAppSignatureMD5() { - return getAppSignatureMD5(Utils.getApp().getPackageName()); + public static List getAppSignaturesMD5() { + return getAppSignaturesMD5(Utils.getApp().getPackageName()); } /** @@ -596,11 +615,10 @@ 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"); + public static List getAppSignaturesMD5(final String packageName) { + return getAppSignaturesHash(packageName, "MD5"); } - /** * Return the application's user-ID. * @@ -625,12 +643,17 @@ public static int getAppUid(String pkgName) { } } - 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; } /** 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 3fe852bf70..eb0a6709fb 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 @@ -387,6 +387,19 @@ public static boolean isEmulator() { return false; } + /** + * 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; 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 2e3a985124..ff74f6c655 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 @@ -210,7 +210,7 @@ public static void launchAppDetailsSettings() { * @return the single {@link PermissionUtils} instance */ public static PermissionUtils permissionGroup(@PermissionGroup final String... permissions) { - return new PermissionUtils(permissions); + return permission(permissions); } /** diff --git a/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java b/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java index a0203f78fc..234973ef5b 100644 --- a/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java +++ b/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java @@ -2,6 +2,8 @@ import android.support.v4.util.LongSparseArray; import android.support.v4.util.SimpleArrayMap; +import android.text.Editable; +import android.text.SpannableStringBuilder; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; From 573843b42f6884c4d6ae2fc1763da1138467766c Mon Sep 17 00:00:00 2001 From: Blankj Date: Wed, 28 Oct 2020 15:26:41 +0800 Subject: [PATCH 20/61] see 10/28 log --- CHANGELOG.md | 1 + buildSrc/src/main/groovy/Config.groovy | 4 ++-- lib/utilcode/README-CN.md | 4 ++-- lib/utilcode/README.md | 4 ++-- .../src/main/java/com/blankj/utilcode/util/BusUtils.java | 3 +-- .../test/java/com/blankj/utilcode/util/ObjectUtilsTest.java | 2 -- lib/utildebug/build.gradle | 4 ++++ 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2850fa22fe..2299a6702e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,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. diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index c707febcbd..e41d37e9b8 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -14,8 +14,8 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_002 - static versionName = '1.30.2'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_003 + static versionName = '1.30.3'// E.g. 1.9.72 => 1,009,072 // lib version static gradlePluginVersion = '3.5.0' diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index 15f6af4970..edfdcb3815 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.2' +implementation 'com.blankj:utilcode:1.30.3' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.2' +implementation 'com.blankj:utilcodex:1.30.3' ``` diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index f85e0b5fac..71ec0bcd3d 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.2' +implementation 'com.blankj:utilcode:1.30.3' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.2' +implementation 'com.blankj:utilcodex:1.30.3' ``` 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 adb88cc697..0eb9ec86fa 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,7 +8,6 @@ import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -357,7 +356,7 @@ private void postStickyInner(final String tag, final Object arg) { 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); diff --git a/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java b/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java index 234973ef5b..a0203f78fc 100644 --- a/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java +++ b/lib/utilcode/src/test/java/com/blankj/utilcode/util/ObjectUtilsTest.java @@ -2,8 +2,6 @@ import android.support.v4.util.LongSparseArray; import android.support.v4.util.SimpleArrayMap; -import android.text.Editable; -import android.text.SpannableStringBuilder; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; diff --git a/lib/utildebug/build.gradle b/lib/utildebug/build.gradle index 8a06562880..04ea90802f 100644 --- a/lib/utildebug/build.gradle +++ b/lib/utildebug/build.gradle @@ -1,3 +1,7 @@ +afterEvaluate { + verifyReleaseResources.enabled(false) +} + dependencies { implementation Config.depConfig.lib_utilcode.dep implementation Config.depConfig.swipe_panel.dep From 74155c92ca81242a6ec80bf53a162fa7997e2023 Mon Sep 17 00:00:00 2001 From: Blankj Date: Thu, 29 Oct 2020 20:03:20 +0800 Subject: [PATCH 21/61] see 10/29 log --- CHANGELOG.md | 1 + buildSrc/src/main/groovy/Config.groovy | 4 +- lib/utilcode/README-CN.md | 4 +- lib/utilcode/README.md | 4 +- .../blankj/utilcode/util/MessengerUtils.java | 19 +++++- .../blankj/utilcode/util/ServiceUtils.java | 59 +++++++++++++++++-- 6 files changed, 76 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2299a6702e..deda0c0468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* `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. diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index e41d37e9b8..ec58830c02 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -14,8 +14,8 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_003 - static versionName = '1.30.3'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_004 + static versionName = '1.30.4'// E.g. 1.9.72 => 1,009,072 // lib version static gradlePluginVersion = '3.5.0' diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index edfdcb3815..9cff770bcf 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.3' +implementation 'com.blankj:utilcode:1.30.4' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.3' +implementation 'com.blankj:utilcodex:1.30.4' ``` diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index 71ec0bcd3d..caeb4623af 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.3' +implementation 'com.blankj:utilcode:1.30.4' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.3' +implementation 'com.blankj:utilcodex:1.30.4' ``` 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 e6ec4eec2a..3b7a0fbb2b 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 @@ -6,6 +6,7 @@ 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; @@ -48,8 +49,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) { @@ -118,13 +118,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; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ServiceUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ServiceUtils.java index 6a1087f8ff..d82a879e44 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ServiceUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ServiceUtils.java @@ -31,7 +31,7 @@ private ServiceUtils() { * * @return all of the services are running */ - public static Set getAllRunningServices() { + public static Set getAllRunningServices() { ActivityManager am = (ActivityManager) Utils.getApp().getSystemService(Context.ACTIVITY_SERVICE); List info = am.getRunningServices(0x7FFFFFFF); Set names = new HashSet<>(); @@ -61,8 +61,16 @@ public static void startService(@NonNull final String className) { * @param cls The service class. */ public static void startService(@NonNull final Class cls) { + startService(new Intent(Utils.getApp(), cls)); + } + + /** + * Start the service. + * + * @param intent The intent. + */ + public static void startService(Intent intent) { try { - Intent intent = new Intent(Utils.getApp(), cls); intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Utils.getApp().startForegroundService(intent); @@ -96,8 +104,22 @@ public static boolean stopService(@NonNull final String className) { * @return {@code true}: success
{@code false}: fail */ public static boolean stopService(@NonNull final Class cls) { - Intent intent = new Intent(Utils.getApp(), cls); - return Utils.getApp().stopService(intent); + return stopService(new Intent(Utils.getApp(), cls)); + } + + /** + * Stop the service. + * + * @param intent The intent. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean stopService(@NonNull Intent intent) { + try { + return Utils.getApp().stopService(intent); + } catch (Exception e) { + e.printStackTrace(); + return false; + } } /** @@ -145,8 +167,33 @@ public static void bindService(@NonNull final String className, public static void bindService(@NonNull final Class cls, @NonNull final ServiceConnection conn, final int flags) { - Intent intent = new Intent(Utils.getApp(), cls); - Utils.getApp().bindService(intent, conn, flags); + bindService(new Intent(Utils.getApp(), cls), conn, flags); + } + + /** + * Bind the service. + * + * @param intent The intent. + * @param conn The ServiceConnection object. + * @param flags Operation options for the binding. + *
    + *
  • 0
  • + *
  • {@link Context#BIND_AUTO_CREATE}
  • + *
  • {@link Context#BIND_DEBUG_UNBIND}
  • + *
  • {@link Context#BIND_NOT_FOREGROUND}
  • + *
  • {@link Context#BIND_ABOVE_CLIENT}
  • + *
  • {@link Context#BIND_ALLOW_OOM_MANAGEMENT}
  • + *
  • {@link Context#BIND_WAIVE_PRIORITY}
  • + *
+ */ + public static void bindService(@NonNull final Intent intent, + @NonNull final ServiceConnection conn, + final int flags) { + try { + Utils.getApp().bindService(intent, conn, flags); + } catch (Exception e) { + e.printStackTrace(); + } } /** From e6ec42f72adfe3351f9280ddce4027b2b98801b4 Mon Sep 17 00:00:00 2001 From: Blankj Date: Fri, 6 Nov 2020 14:28:45 +0800 Subject: [PATCH 22/61] see 11/06 log --- buildSrc/src/main/groovy/Config.groovy | 2 +- .../blankj/utilcode/pkg/feature/mvp/MvpActivity.java | 2 -- .../com/blankj/utilcode/pkg/feature/mvp/MvpModel.java | 2 +- .../pkg/feature/mvp/{IMvp.java => MvpMvp.java} | 2 +- .../blankj/utilcode/pkg/feature/mvp/MvpPresenter.java | 2 +- .../com/blankj/utilcode/pkg/feature/mvp/MvpView.java | 3 +-- .../src/main/java/com/blankj/base/mvp/BaseModel.java | 4 ---- .../main/java/com/blankj/base/mvp/BasePresenter.java | 6 ------ .../java/com/blankj/utilcode/util/CleanUtils.java | 11 +++++++++++ plugin/api-gradle-plugin/CHANGELOG.md | 3 +++ plugin/api-gradle-plugin/README.md | 2 +- .../src/main/java/com/blankj/api/ApiClassVisitor.java | 7 +++---- plugin/bus-gradle-plugin/README.md | 2 +- 13 files changed, 24 insertions(+), 24 deletions(-) rename feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/{IMvp.java => MvpMvp.java} (94%) diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index ec58830c02..db0ca894bf 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -53,7 +53,7 @@ class Config { // 上传新版本插件更新 pluginPath 中的版本号,并设置 isApply = false // 通过 mavenLocal 上传本地版本,设置 isApply = true 即可应用插件来调试,最后通过 bintrayUpload 来发布插件 - plugin_api : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:api-gradle-plugin:1.4", pluginId: "com.blankj.api"), + plugin_api : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:api-gradle-plugin:latest.release", pluginId: "com.blankj.api"), //./gradlew clean :plugin_api-gradle-plugin:mavenLocal // 上传到本地 mavenLocal //./gradlew clean :plugin_api-gradle-plugin:bintrayUpload // 上传到 jcenter plugin_bus : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:bus-gradle-plugin:2.6", pluginId: "com.blankj.bus"), diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java index 813431f6f8..7aa5fe26b1 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java @@ -1,7 +1,5 @@ package com.blankj.utilcode.pkg.feature.mvp; -import android.arch.lifecycle.ViewModel; -import android.arch.lifecycle.ViewModelProvider; import android.content.Context; import android.content.Intent; import android.os.Bundle; 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 8697f11c1d..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,7 +12,7 @@ * desc : *
*/ -public class MvpModel extends BaseModel implements IMvp.Model { +public class MvpModel extends BaseModel implements MvpMvp.Model { private int index; diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/IMvp.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpMvp.java similarity index 94% rename from feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/IMvp.java rename to feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpMvp.java index 4e8edc023e..d0335ef203 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/IMvp.java +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpMvp.java @@ -10,7 +10,7 @@ * desc : *
*/ -public interface IMvp { +public interface MvpMvp { interface View { void setLoadingVisible(boolean visible); diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java index 01990aa3af..fcb68bd3ed 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java @@ -13,7 +13,7 @@ *
*/ public class MvpPresenter extends BasePresenter - implements IMvp.Presenter { + implements MvpMvp.Presenter { @Override public void onBindView() { diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java index 054cd7ade9..e916398e48 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java @@ -6,7 +6,6 @@ import com.blankj.base.mvp.BaseView; import com.blankj.utilcode.pkg.R; -import com.blankj.utilcode.pkg.feature.fragment.FragmentActivity; import com.blankj.utilcode.util.ClickUtils; import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.SizeUtils; @@ -22,7 +21,7 @@ *
*/ public class MvpView extends BaseView - implements IMvp.View { + implements MvpMvp.View { private TextView mvpTv; private TextView mvpMeasureWidthTv; 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 84c930fd74..1623f90254 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,7 +1,5 @@ package com.blankj.base.mvp; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; import android.support.annotation.CallSuper; import android.util.Log; @@ -15,8 +13,6 @@ */ public abstract class BaseModel { - LiveData mData = new MutableLiveData<>(); - private static final String TAG = BaseView.TAG; public abstract void onCreate(); 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 2c6806708a..cc3f84cb48 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,7 +1,5 @@ package com.blankj.base.mvp; -import android.arch.lifecycle.ViewModel; -import android.arch.lifecycle.ViewModelProvider; import android.support.annotation.CallSuper; import android.util.Log; @@ -69,8 +67,4 @@ public void onDestroy() { public boolean isAlive() { return isAlive; } - - public void getSafeData() { - new ViewModelProvider(getView().getActivity(), new ViewModelProvider.NewInstanceFactory()).get(ViewModel.class); - } } 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..10fe1d84c1 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,6 +1,10 @@ package com.blankj.utilcode.util; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; import android.os.Environment; +import android.support.annotation.RequiresApi; import java.io.File; @@ -89,4 +93,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/plugin/api-gradle-plugin/CHANGELOG.md b/plugin/api-gradle-plugin/CHANGELOG.md index 8aa9190f8b..18476ef1e6 100644 --- a/plugin/api-gradle-plugin/CHANGELOG.md +++ b/plugin/api-gradle-plugin/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## v1.5(2020/11/06) +对非 mock 的 visitor 的修复 + ## v1.4(2020/05/19) 重新发布,因为上个版本从阿里云仓库拉取是有问题的 diff --git a/plugin/api-gradle-plugin/README.md b/plugin/api-gradle-plugin/README.md index ed673a5070..5350bc5426 100644 --- a/plugin/api-gradle-plugin/README.md +++ b/plugin/api-gradle-plugin/README.md @@ -30,7 +30,7 @@ buildscript { dependencies { ... - classpath 'com.blankj:api-gradle-plugin:1.4' + classpath 'com.blankj:api-gradle-plugin:latest.release' } } ``` diff --git a/plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiClassVisitor.java b/plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiClassVisitor.java index 443f0a846d..7f71e7919a 100644 --- a/plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiClassVisitor.java +++ b/plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiClassVisitor.java @@ -25,7 +25,6 @@ public class ApiClassVisitor extends ClassVisitor { private boolean hasAnnotation; private boolean isMock; private String mApiUtilsClass; - public String errorStr; public ApiClassVisitor(ClassVisitor classVisitor, Map apiImplMap, List apiClasses, String apiUtilsClass) { super(Opcodes.ASM5, classVisitor); @@ -65,10 +64,10 @@ public void visitEnd() { if (hasAnnotation) { if (!isMock) {// 如果不是 mock 的话 ApiInfo apiInfo = mApiImplMap.get(superClassName); - if (apiInfo == null) { + if (apiInfo == null || apiInfo.isMock) {// 不存在或者之前存在的是 mock mApiImplMap.put(superClassName, new ApiInfo(className, false)); - } else {// 存在一个 api 多个实现就报错 - errorStr = "<" + className + "> and <" + apiInfo.implApiClass + "> impl same api of <" + superClassName + ">"; + } else {// 存在一个 api 多个非 mock 实现就报错 + throw new IllegalArgumentException("<" + className + "> and <" + apiInfo.implApiClass + "> impl same api of <" + superClassName + ">"); } } else {// mock 的话,如果 map 中已存在就不覆盖了 if (!mApiImplMap.containsKey(superClassName)) { diff --git a/plugin/bus-gradle-plugin/README.md b/plugin/bus-gradle-plugin/README.md index ec039ca8fd..a2d0362f39 100644 --- a/plugin/bus-gradle-plugin/README.md +++ b/plugin/bus-gradle-plugin/README.md @@ -19,7 +19,7 @@ buildscript { dependencies { ... - classpath 'com.blankj:bus-gradle-plugin:2.6' + classpath 'com.blankj:bus-gradle-plugin:latest.release' } } ``` From 27cf719c188603a1f9109c4bf1bcfb7949903b02 Mon Sep 17 00:00:00 2001 From: Blankj Date: Fri, 13 Nov 2020 15:31:48 +0800 Subject: [PATCH 23/61] see 11/13 log --- CHANGELOG.md | 1 + buildSrc/src/main/groovy/Config.groovy | 6 +- .../utilcode/pkg/src/main/AndroidManifest.xml | 1 + .../pkg/feature/network/NetworkActivity.kt | 41 ++++- .../com/blankj/subutil/util/BatteryUtils.java | 2 - lib/utilcode/README-CN.md | 7 +- lib/utilcode/README.md | 7 +- .../com/blankj/utilcode/util/CrashUtils.java | 1 - .../com/blankj/utilcode/util/DeviceUtils.java | 13 +- .../blankj/utilcode/util/FragmentUtils.java | 116 +++++++----- .../blankj/utilcode/util/MessengerUtils.java | 7 + .../blankj/utilcode/util/NetworkUtils.java | 171 +++++++++++++++++- .../utilcode/util/NotificationUtils.java | 13 +- .../com/blankj/utilcode/util/TimeUtils.java | 2 +- .../util/UtilsActivityLifecycleImpl.java | 45 ++++- .../com/blankj/utilcode/util/UtilsBridge.java | 10 + 16 files changed, 372 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index deda0c0468..913ee7b7ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* `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. diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index db0ca894bf..1d9b9cd6cd 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -14,8 +14,8 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_004 - static versionName = '1.30.4'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_005 + static versionName = '1.30.5'// E.g. 1.9.72 => 1,009,072 // lib version static gradlePluginVersion = '3.5.0' @@ -53,7 +53,7 @@ class Config { // 上传新版本插件更新 pluginPath 中的版本号,并设置 isApply = false // 通过 mavenLocal 上传本地版本,设置 isApply = true 即可应用插件来调试,最后通过 bintrayUpload 来发布插件 - plugin_api : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:api-gradle-plugin:latest.release", pluginId: "com.blankj.api"), + plugin_api : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:api-gradle-plugin:1.5", pluginId: "com.blankj.api"), //./gradlew clean :plugin_api-gradle-plugin:mavenLocal // 上传到本地 mavenLocal //./gradlew clean :plugin_api-gradle-plugin:bintrayUpload // 上传到 jcenter plugin_bus : new DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:bus-gradle-plugin:2.6", pluginId: "com.blankj.bus"), diff --git a/feature/utilcode/pkg/src/main/AndroidManifest.xml b/feature/utilcode/pkg/src/main/AndroidManifest.xml index f77ad3d953..8da0667a23 100644 --- a/feature/utilcode/pkg/src/main/AndroidManifest.xml +++ b/feature/utilcode/pkg/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ + diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt index f0c9962b2d..452040376d 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt @@ -2,13 +2,17 @@ package com.blankj.utilcode.pkg.feature.network import android.content.Context import android.content.Intent +import android.net.wifi.ScanResult +import android.net.wifi.WifiManager import android.os.Bundle import android.view.View import com.blankj.common.activity.CommonActivity +import com.blankj.common.helper.PermissionHelper import com.blankj.common.item.CommonItem import com.blankj.common.item.CommonItemClick import com.blankj.common.item.CommonItemSwitch import com.blankj.common.item.CommonItemTitle +import com.blankj.utilcode.constant.PermissionConstants import com.blankj.utilcode.pkg.R import com.blankj.utilcode.util.* @@ -24,12 +28,24 @@ class NetworkActivity : CommonActivity(), NetworkUtils.OnNetworkStatusChangedLis companion object { fun start(context: Context) { - val starter = Intent(context, NetworkActivity::class.java) - context.startActivity(starter) + PermissionHelper.request(context, object : PermissionUtils.SimpleCallback { + override fun onGranted() { + val starter = Intent(context, NetworkActivity::class.java) + context.startActivity(starter) + } + + override fun onDenied() { + } + }, PermissionConstants.LOCATION) } } private lateinit var itemsTask: ThreadUtils.SimpleTask>> + private lateinit var wifiScanResultItem: CommonItemTitle + private val consumer = Utils.Consumer { t -> + wifiScanResultItem.setContent(scanResults2String(t.filterResults)) + wifiScanResultItem.update() + } override fun bindTitleRes(): Int { return R.string.demo_network @@ -51,6 +67,7 @@ class NetworkActivity : CommonActivity(), NetworkUtils.OnNetworkStatusChangedLis override fun bindItems(): List> { if (ThreadUtils.isMainThread()) return arrayListOf() + wifiScanResultItem = CommonItemTitle("getWifiScanResult", scanResults2String(NetworkUtils.getWifiScanResult().filterResults)) return CollectionUtils.newArrayList( CommonItemTitle("isConnected", NetworkUtils.isConnected().toString()), CommonItemTitle("getMobileDataEnabled", NetworkUtils.getMobileDataEnabled().toString()), @@ -72,10 +89,19 @@ class NetworkActivity : CommonActivity(), NetworkUtils.OnNetworkStatusChangedLis CommonItemTitle("isWifiAvailable", NetworkUtils.isWifiAvailable().toString()), CommonItemTitle("isAvailable", NetworkUtils.isAvailable().toString()), CommonItemTitle("getBaiduDomainAddress", NetworkUtils.getDomainAddress("baidu.com")), + wifiScanResultItem, CommonItemSwitch( R.string.network_wifi_enabled, - { NetworkUtils.getWifiEnabled() }, + { + val wifiEnabled = NetworkUtils.getWifiEnabled() + if (wifiEnabled) { + NetworkUtils.addOnWifiChangedConsumer(consumer) + } else { + NetworkUtils.removeOnWifiChangedConsumer(consumer) + } + wifiEnabled + }, { NetworkUtils.setWifiEnabled(it) ThreadUtils.executeByIo(getItemsTask()) @@ -112,5 +138,14 @@ class NetworkActivity : CommonActivity(), NetworkUtils.OnNetworkStatusChangedLis super.onDestroy() ThreadUtils.cancel(itemsTask) NetworkUtils.unregisterNetworkStatusChangedListener(this) + NetworkUtils.removeOnWifiChangedConsumer(consumer) + } + + private fun scanResults2String(results: List): String { + val sb: StringBuilder = StringBuilder() + for (result in results) { + sb.append(String.format("${result.SSID}, Level: ${WifiManager.calculateSignalLevel(result.level, 4)}\n")) + } + return sb.toString() } } diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java b/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java index f85091e649..0e2fc571b4 100644 --- a/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java +++ b/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java @@ -76,7 +76,6 @@ private static BatteryChangedReceiver getInstance() { void registerListener(final OnBatteryStatusChangedListener listener) { if (listener == null) return; ThreadUtils.runOnUiThread(new Runnable() { - @SuppressLint("MissingPermission") @Override public void run() { int preSize = mListeners.size(); @@ -109,7 +108,6 @@ public void run() { }); } - @SuppressLint("MissingPermission") @Override public void onReceive(Context context, final Intent intent) { if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index 9cff770bcf..a50fef56c8 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.4' +implementation 'com.blankj:utilcode:1.30.5' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.4' +implementation 'com.blankj:utilcodex:1.30.5' ``` @@ -721,6 +721,9 @@ getServerAddressByWifi : 根据 WiFi 获取服务端 IP 地址 registerNetworkStatusChangedListener : 注册网络状态改变监听器 isRegisteredNetworkStatusChangedListener: 判断是否注册网络状态改变监听器 unregisterNetworkStatusChangedListener : 注销网络状态改变监听器 +getWifiScanResult : 获取 WIFI 列表 +addOnWifiChangedConsumer : 增加 WIFI 改变监听 +removeOnWifiChangedConsumer : 移除 WIFI 改变监听 ``` * ### 通知相关 -> [NotificationUtils.java][notification.java] -> [Demo][notification.demo] diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index caeb4623af..55ad2d880a 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.4' +implementation 'com.blankj:utilcode:1.30.5' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.4' +implementation 'com.blankj:utilcodex:1.30.5' ``` @@ -721,6 +721,9 @@ getServerAddressByWifi registerNetworkStatusChangedListener isRegisteredNetworkStatusChangedListener unregisterNetworkStatusChangedListener +getWifiScanResult +addOnWifiChangedConsumer +removeOnWifiChangedConsumer ``` * ### About Notification -> [NotificationUtils.java][notification.java] -> [Demo][notification.demo] 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 8154d9e069..d267bc5c33 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 @@ -30,7 +30,6 @@ private CrashUtils() { /** * Initialization. */ - @SuppressLint("MissingPermission") public static void init() { init(""); } 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 eb0a6709fb..e5c4b204e8 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 @@ -113,7 +113,7 @@ 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 (!TextUtils.isEmpty(macAddress) || getWifiEnabled()) return macAddress; @@ -151,7 +151,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)) { @@ -190,7 +190,7 @@ private static boolean isAddressNotInExcepts(final String address, final String. return true; } - @SuppressLint({"MissingPermission", "HardwareIds"}) + @RequiresPermission(ACCESS_WIFI_STATE) private static String getMacAddressByWifiInfo() { try { final WifiManager wifi = (WifiManager) Utils.getApp() @@ -198,6 +198,7 @@ private static String getMacAddressByWifiInfo() { if (wifi != null) { final WifiInfo info = wifi.getConnectionInfo(); if (info != null) { + @SuppressLint("HardwareIds") String macAddress = info.getMacAddress(); if (!TextUtils.isEmpty(macAddress)) { return macAddress; @@ -412,7 +413,6 @@ public static boolean isDevelopmentSettingsEnabled() { * * @return the unique device id */ - @SuppressLint({"MissingPermission", "HardwareIds"}) public static String getUniqueDeviceId() { return getUniqueDeviceId("", true); } @@ -426,7 +426,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); } @@ -440,7 +439,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); } @@ -455,7 +453,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); @@ -486,7 +483,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/FragmentUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FragmentUtils.java index 0916aa3b1d..3e56907eb2 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 @@ -17,6 +17,7 @@ import android.view.View; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -301,7 +302,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 +490,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 +500,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 +513,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 +523,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 +536,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 List fragments) { - showHide(fragments.get(showIndex), fragments); + public static void showHide(final int showIndex, @NonNull final Fragment... fragments) { + showHide(fragments[showIndex], fragments); } /** @@ -562,22 +566,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 +586,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 +601,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 +1395,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 +1405,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 +1415,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 +1447,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; 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 3b7a0fbb2b..a764eb50b6 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,6 +1,7 @@ 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; @@ -296,6 +297,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) { 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 f9ba566cc9..8f874dbf38 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 @@ -7,6 +7,7 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; @@ -22,12 +23,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; @@ -686,6 +693,7 @@ public static String getSSID() { * * @param listener The status of network changed listener */ + @RequiresPermission(ACCESS_NETWORK_STATE) public static void registerNetworkStatusChangedListener(final OnNetworkStatusChangedListener listener) { NetworkChangedReceiver.getInstance().registerListener(listener); } @@ -709,6 +717,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 + List results = 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() { @@ -718,11 +843,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); @@ -754,13 +880,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; @@ -863,4 +989,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..48e22a3e62 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 @@ -91,21 +91,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/TimeUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java index d328524c36..2ab5370c82 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java @@ -1525,7 +1525,7 @@ public static String getChineseZodiac(final int year) { private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22}; private static final String[] ZODIAC = { "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", - "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座" + "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座" }; /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java index b3ecdf55b8..272eddcb45 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java @@ -7,6 +7,7 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import android.view.Window; import android.view.WindowManager; @@ -195,6 +196,9 @@ Application getApplicationByReflect() { /////////////////////////////////////////////////////////////////////////// // lifecycle start /////////////////////////////////////////////////////////////////////////// + @Override + public void onActivityPreCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {/**/} + @Override public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) { LanguageUtils.applyLanguage(activity); @@ -203,6 +207,12 @@ public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceSt consumeActivityLifecycleCallbacks(activity, Lifecycle.Event.ON_CREATE); } + @Override + public void onActivityPostCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {/**/} + + @Override + public void onActivityPreStarted(@NonNull Activity activity) {/**/} + @Override public void onActivityStarted(@NonNull Activity activity) { if (!mIsBackground) { @@ -216,6 +226,12 @@ public void onActivityStarted(@NonNull Activity activity) { consumeActivityLifecycleCallbacks(activity, Lifecycle.Event.ON_START); } + @Override + public void onActivityPostStarted(@NonNull Activity activity) {/**/} + + @Override + public void onActivityPreResumed(@NonNull Activity activity) {/**/} + @Override public void onActivityResumed(@NonNull final Activity activity) { setTopActivity(activity); @@ -227,11 +243,23 @@ public void onActivityResumed(@NonNull final Activity activity) { consumeActivityLifecycleCallbacks(activity, Lifecycle.Event.ON_RESUME); } + @Override + public void onActivityPostResumed(@NonNull Activity activity) {/**/} + + @Override + public void onActivityPrePaused(@NonNull Activity activity) {/**/} + @Override public void onActivityPaused(@NonNull Activity activity) { consumeActivityLifecycleCallbacks(activity, Lifecycle.Event.ON_PAUSE); } + @Override + public void onActivityPostPaused(@NonNull Activity activity) {/**/} + + @Override + public void onActivityPreStopped(@NonNull Activity activity) {/**/} + @Override public void onActivityStopped(Activity activity) { if (activity.isChangingConfigurations()) { @@ -248,7 +276,19 @@ public void onActivityStopped(Activity activity) { } @Override - public void onActivitySaveInstanceState(@NonNull Activity activity, Bundle outState) {/**/} + public void onActivityPostStopped(@NonNull Activity activity) {/**/} + + @Override + public void onActivityPreSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {/**/} + + @Override + public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {/**/} + + @Override + public void onActivityPostSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {/**/} + + @Override + public void onActivityPreDestroyed(@NonNull Activity activity) {/**/} @Override public void onActivityDestroyed(@NonNull Activity activity) { @@ -256,6 +296,9 @@ public void onActivityDestroyed(@NonNull Activity activity) { UtilsBridge.fixSoftInputLeaks(activity); consumeActivityLifecycleCallbacks(activity, Lifecycle.Event.ON_DESTROY); } + + @Override + public void onActivityPostDestroyed(@NonNull Activity activity) {/**/} /////////////////////////////////////////////////////////////////////////// // lifecycle end /////////////////////////////////////////////////////////////////////////// diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java index 86ba24bd89..5361fdc1de 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.app.Application; +import android.app.Notification; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -14,6 +15,7 @@ import android.support.annotation.RequiresApi; import android.support.annotation.RequiresPermission; import android.support.annotation.StringRes; +import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.view.View; @@ -418,6 +420,14 @@ static void fixSoftInputLeaks(final Activity activity) { KeyboardUtils.fixSoftInputLeaks(activity); } + /////////////////////////////////////////////////////////////////////////// + // NotificationUtils + /////////////////////////////////////////////////////////////////////////// + static Notification getNotification(NotificationUtils.ChannelConfig channelConfig, + Utils.Consumer consumer) { + return NotificationUtils.getNotification(channelConfig, consumer); + } + /////////////////////////////////////////////////////////////////////////// // PermissionUtils /////////////////////////////////////////////////////////////////////////// From be7c7c27f4191a9a741d6c63a7ef6d7e2c14e449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=9C=9D=E6=97=AD?= <974577817@qq.com> Date: Fri, 4 Dec 2020 11:34:42 +0800 Subject: [PATCH 24/61] Update ColorUtils.java add static to ColorUtils.isLightColor --- .../src/main/java/com/blankj/utilcode/util/ColorUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d894de475b..0b0d9d37f8 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 @@ -211,7 +211,7 @@ public static int getRandomColor(final boolean supportAlpha) { * @param color The color. * @return {@code true}: yes
{@code false}: no */ - public boolean isLightColor(@ColorInt int color) { + 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; } } From 7402e364000fd053b7ee08650a04a8559977ba41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=AD=87=E5=B0=94?= Date: Sun, 10 Jan 2021 16:54:25 +0430 Subject: [PATCH 25/61] Added new methods (features) Added 6 new very useful methods. 1. getScreenXDpi() which returns the Width (X) density in DPI. 2. getScreenYDpi() which returns the Height (Y) density in DPI. 3. calculateDistanceByX() which returns the distance between the given View's X (start point of View's width) and the screen width. 4. calculateDistanceByY() which returns the distance between the given View's Y (start point of View's height) and the screen height. 5. getViewX() which returns the X coordinate of the given View on the screen. 6. getViewY() which returns the Y coordinate of the given View on the screen. --- .../com/blankj/utilcode/util/ScreenUtils.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java index b5cad7ef99..cb742b7a7d 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java @@ -112,6 +112,74 @@ public static float getScreenDensity() { public static int getScreenDensityDpi() { return Resources.getSystem().getDisplayMetrics().densityDpi; } + + + + + /** + * Return X (width) of the screen expressed as dots-per-inch. + * + * @return the width of screen density expressed as dots-per-inch + */ + public static int getScreenXDpi() { + return Resources.getSystem().getDisplayMetrics().xdpi; + } + + /** + * Return Y (height) of the screen expressed as dots-per-inch. + * + * @return the height of screen density expressed as dots-per-inch + */ + public static int getScreenYDpi() { + return Resources.getSystem().getDisplayMetrics().ydpi; + } + + + + /** + * Return the distance between the given View's X (start point of View's width) and the screen width. + * + * @return the distance between the given View's X (start point of View's width) and the screen width. + */ + public float calculateDistanceByX(View view) { + int[] point = new int[0]; + view.getLocationOnScreen(point); + return (getScreenWidth() - point[0]).toFloat(); + } + + /** + * Return the distance between the given View's Y (start point of View's height) and the screen height. + * + * @return the distance between the given View's Y (start point of View's height) and the screen height. + */ + public float calculateDistanceByY(View view) { + int[] point = new int[0]; + view.getLocationOnScreen(point); + return (getScreenHeight() - point[1]).toFloat(); + } + + /** + * Return the X coordinate of the given View on the screen. + * + * @return X coordinate of the given View on the screen. + */ + public int getViewX(View view){ + int[] point = new int[0]; + view.getLocationOnScreen(point); + return point[0]; + } + + /** + * Return the Y coordinate of the given View on the screen. + * + * @return Y coordinate of the given View on the screen. + */ + public int getViewY(View view){ + int[] point = new int[0]; + view.getLocationOnScreen(point); + return point[1]; + } + /** * Set full screen. From fd2d59aa451d0a1c038757d68e5387ef5c7d4230 Mon Sep 17 00:00:00 2001 From: yuruxuan <544324974@qq.com> Date: Mon, 1 Feb 2021 13:43:30 +0800 Subject: [PATCH 26/61] add environment variable --- .../com/blankj/utilcode/util/ShellUtils.java | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ShellUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ShellUtils.java index 1f2d50888b..a4f1e4fa81 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ShellUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ShellUtils.java @@ -133,6 +133,21 @@ public static CommandResult execCmd(final String command, final boolean isRooted return execCmd(new String[]{command}, isRooted, true); } + /** + * Execute the command. + * + * @param command The command. + * @param envp The environment variable settings. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, final List envp, final boolean isRooted) { + return execCmd(new String[]{command}, + envp == null ? null : envp.toArray(new String[]{}), + isRooted, + true); + } + /** * Execute the command. * @@ -144,6 +159,23 @@ public static CommandResult execCmd(final List commands, final boolean i return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true); } + /** + * Execute the command. + * + * @param commands The commands. + * @param envp The environment variable settings. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final List commands, + final List envp, + final boolean isRooted) { + return execCmd(commands == null ? null : commands.toArray(new String[]{}), + envp == null ? null : envp.toArray(new String[]{}), + isRooted, + true); + } + /** * Execute the command. * @@ -169,6 +201,40 @@ public static CommandResult execCmd(final String command, return execCmd(new String[]{command}, isRooted, isNeedResultMsg); } + /** + * Execute the command. + * + * @param command The command. + * @param envp The environment variable settings. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, + final List envp, + final boolean isRooted, + final boolean isNeedResultMsg) { + return execCmd(new String[]{command}, envp == null ? null : envp.toArray(new String[]{}), + isRooted, + isNeedResultMsg); + } + + /** + * Execute the command. + * + * @param command The command. + * @param envp The environment variable settings array. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, + final String[] envp, + final boolean isRooted, + final boolean isNeedResultMsg) { + return execCmd(new String[]{command}, envp, isRooted, isNeedResultMsg); + } + /** * Execute the command. * @@ -196,6 +262,26 @@ public static CommandResult execCmd(final List commands, public static CommandResult execCmd(final String[] commands, final boolean isRooted, final boolean isNeedResultMsg) { + return execCmd(commands, null, isRooted, isNeedResultMsg); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param envp Array of strings, each element of which + * has environment variable settings in the format + * name=value, or + * null if the subprocess should inherit + * the environment of the current process. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String[] commands, + final String[] envp, + final boolean isRooted, + final boolean isNeedResultMsg) { int result = -1; if (commands == null || commands.length == 0) { return new CommandResult(result, "", ""); @@ -207,7 +293,7 @@ public static CommandResult execCmd(final String[] commands, StringBuilder errorMsg = null; DataOutputStream os = null; try { - process = Runtime.getRuntime().exec(isRooted ? "su" : "sh"); + process = Runtime.getRuntime().exec(isRooted ? "su" : "sh", envp, null); os = new DataOutputStream(process.getOutputStream()); for (String command : commands) { if (command == null) continue; From 28f24faf597ef92771d97780eac7d8e69ad145a4 Mon Sep 17 00:00:00 2001 From: Blankj Date: Mon, 22 Feb 2021 00:07:51 +0800 Subject: [PATCH 27/61] see 02/22 log --- CHANGELOG.md | 2 + buildSrc/src/main/groovy/Config.groovy | 4 +- .../launcher/app/src/main/AndroidManifest.xml | 1 + .../java/com/blankj/main/pkg/MainActivity.kt | 4 +- .../utilcode/pkg/feature/api/ApiActivity.kt | 4 +- .../pkg/feature/clean/CleanActivity.kt | 7 +- .../pkg/feature/keyboard/KeyboardActivity.kt | 3 +- .../pkg/feature/language/LanguageActivity.kt | 3 + .../pkg/feature/phone/PhoneActivity.kt | 4 +- .../pkg/feature/toast/ToastActivity.kt | 3 + .../src/main/res/values-en-rUS/strings.xml | 1 + .../src/main/res/values-zh-rCN/strings.xml | 1 + .../pkg/src/main/res/values/strings.xml | 4 + .../java/com/blankj/base/BaseFragment.java | 2 +- .../com/blankj/subutil/util/BatteryUtils.java | 30 +- lib/utilcode/README-CN.md | 4 +- lib/utilcode/README.md | 4 +- .../utilcode/constant/RegexConstants.java | 11 +- .../blankj/utilcode/util/ActivityUtils.java | 29 +- .../utilcode/util/AdaptScreenUtils.java | 17 +- .../com/blankj/utilcode/util/ApiUtils.java | 6 +- .../com/blankj/utilcode/util/AppUtils.java | 56 +- .../com/blankj/utilcode/util/ArrayUtils.java | 529 +++++++++++------- .../com/blankj/utilcode/util/BarUtils.java | 20 +- .../blankj/utilcode/util/BrightnessUtils.java | 2 +- .../com/blankj/utilcode/util/BusUtils.java | 16 +- .../utilcode/util/CacheDiskStaticUtils.java | 100 ++-- .../utilcode/util/CacheDoubleUtils.java | 56 +- .../blankj/utilcode/util/FragmentUtils.java | 1 + .../com/blankj/utilcode/util/ImageUtils.java | 103 +++- .../com/blankj/utilcode/util/IntentUtils.java | 13 +- .../com/blankj/utilcode/util/PhoneUtils.java | 7 +- .../com/blankj/utilcode/util/RomUtils.java | 2 +- .../blankj/utilcode/util/SnackbarUtils.java | 16 +- .../com/blankj/utilcode/util/SpanUtils.java | 16 +- .../com/blankj/utilcode/util/StringUtils.java | 3 +- .../com/blankj/utilcode/util/ThreadUtils.java | 14 +- .../com/blankj/utilcode/util/ToastUtils.java | 145 +++-- .../util/UtilsActivityLifecycleImpl.java | 3 + .../com/blankj/utilcode/util/UtilsBridge.java | 7 +- .../main/res/xml/util_code_provider_paths.xml | 4 - .../utildebug/base/view/BaseContentView.java | 2 + 42 files changed, 854 insertions(+), 405 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 913ee7b7ad..14be8c6656 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +* `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. diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index 1d9b9cd6cd..fd23def7b1 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -14,8 +14,8 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_005 - static versionName = '1.30.5'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_006 + static versionName = '1.30.6'// E.g. 1.9.72 => 1,009,072 // lib version static gradlePluginVersion = '3.5.0' diff --git a/feature/launcher/app/src/main/AndroidManifest.xml b/feature/launcher/app/src/main/AndroidManifest.xml index 19f6313965..4f033c06a6 100644 --- a/feature/launcher/app/src/main/AndroidManifest.xml +++ b/feature/launcher/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:supportsRtl="true" android:theme="@style/AppTheme"> >( CommonItemClick(R.string.core_util, true) { - ApiUtils.getApi(UtilCodeApi::class.java).startUtilCodeActivity(this) + ApiUtils.getApi(UtilCodeApi::class.java)?.startUtilCodeActivity(this) }, CommonItemClick(R.string.sub_util, true) { - ApiUtils.getApi(SubUtilApi::class.java).startSubUtilActivity(this) + ApiUtils.getApi(SubUtilApi::class.java)?.startSubUtilActivity(this) } )) diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt index 0857ceaeac..8e11495b09 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt @@ -35,10 +35,10 @@ class ApiActivity : CommonActivity() { override fun bindItems(): MutableList> { return CollectionUtils.newArrayList( CommonItemClick(R.string.api_invoke_with_params) { - ApiUtils.getApi(OtherModuleApi::class.java).invokeWithParams(OtherModuleApi.ApiBean("params")) + ApiUtils.getApi(OtherModuleApi::class.java)?.invokeWithParams(OtherModuleApi.ApiBean("params")) }, CommonItemClick(R.string.api_invoke_with_return_value) { - ToastUtils.showShort(ApiUtils.getApi(OtherModuleApi::class.java).invokeWithReturnValue().name) + ToastUtils.showShort(ApiUtils.getApi(OtherModuleApi::class.java)?.invokeWithReturnValue()?.name) } ); } diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt index 7185cc33cb..f0b8620eca 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt @@ -3,8 +3,6 @@ package com.blankj.utilcode.pkg.feature.clean import android.content.Context import android.content.Intent import com.blankj.common.activity.CommonActivity -import com.blankj.common.activity.CommonActivityItemsView -import com.blankj.common.activity.CommonActivityTitleView import com.blankj.common.item.CommonItem import com.blankj.common.item.CommonItemClick import com.blankj.utilcode.pkg.R @@ -54,6 +52,11 @@ class CleanActivity : CommonActivity() { showSnackbar(CleanUtils.cleanExternalCache(), externalCacheDir?.absolutePath) }) } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + add(CommonItemClick(R.string.clean_app_user_data) { + CleanUtils.cleanAppUserData() + }) + } } } diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt index b94f66876f..5ed25ae4fe 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt @@ -10,8 +10,7 @@ import com.blankj.common.item.CommonItemClick import com.blankj.common.item.CommonItemTitle import com.blankj.utilcode.pkg.R import com.blankj.utilcode.pkg.helper.DialogHelper -import com.blankj.utilcode.util.CollectionUtils -import com.blankj.utilcode.util.KeyboardUtils +import com.blankj.utilcode.util.* import kotlinx.android.synthetic.main.keyboard_activity.* /** diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt index 0e14482b91..c928da21fa 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt @@ -60,6 +60,9 @@ class LanguageActivity : CommonActivity() { CommonItemClick(R.string.language_apply_english) { LanguageUtils.applyLanguage(Locale.ENGLISH, isRelaunchApp()) }, + CommonItemClick(R.string.language_apply_arabic) { + LanguageUtils.applyLanguage(Locale("ar"), isRelaunchApp()) + }, CommonItemClick(R.string.language_apply_system) { LanguageUtils.applySystemLanguage(isRelaunchApp()) } diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt index cb453b3b89..c9b748cdfa 100644 --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt @@ -54,8 +54,8 @@ class PhoneActivity : CommonActivity() { CommonItemTitle("getSimOperatorName", PhoneUtils.getSimOperatorName()), CommonItemTitle("getSimOperatorByMnc", PhoneUtils.getSimOperatorByMnc()), - CommonItemClick(R.string.phone_dial) { PhoneUtils.dial("10000") }, - CommonItemClick(R.string.phone_call) { PhoneUtils.call("10000") }, + CommonItemClick(R.string.phone_dial) { PhoneUtils.dial("*10000#haha") }, + CommonItemClick(R.string.phone_call) { PhoneUtils.call("*10000#haha") }, CommonItemClick(R.string.phone_send_sms) { PhoneUtils.sendSms("10000", "sendSms") } ) } 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 5d55e3c754..bcb3eadfca 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 @@ -79,6 +79,9 @@ class ToastActivity : CommonActivity() { CommonItemClick(R.string.toast_show_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() }, 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 414fa48424..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 @@ -6,6 +6,7 @@ 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 5cab96988f..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 @@ -6,6 +6,7 @@ 设置简体中文 设置美语 设置英语 + 设置阿拉伯语 设置系统语言 \ 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 ed7e15412f..ccec698647 100644 --- a/feature/utilcode/pkg/src/main/res/values/strings.xml +++ b/feature/utilcode/pkg/src/main/res/values/strings.xml @@ -141,6 +141,7 @@ Clean Internal Databases Clean Internal SP Clean External Cache + cleanAppUserData Click View Scale Default @@ -233,6 +234,7 @@ Apply Simple Chinese Apply American Apply English + Apply Arabic Apply System @@ -341,6 +343,7 @@ Show Custom View Custom View Show Middle + Show Top Cancel Show Toast Dialog Show Toast When Start Activity @@ -351,6 +354,7 @@ Custom Bg Spannable String Middle + Top Add Listener Id 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..354cb0e839 100644 --- a/lib/base/src/main/java/com/blankj/base/BaseFragment.java +++ b/lib/base/src/main/java/com/blankj/base/BaseFragment.java @@ -89,7 +89,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { } else { ft.show(this); } - ft.commitAllowingStateLoss(); + ft.commitNowAllowingStateLoss(); } Bundle bundle = getArguments(); initData(bundle); diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java b/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java index 0e2fc571b4..56e3f36c76 100644 --- a/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java +++ b/lib/subutil/src/main/java/com/blankj/subutil/util/BatteryUtils.java @@ -1,12 +1,14 @@ package com.blankj.subutil.util; -import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; +import android.os.Build; +import android.os.PowerManager; import android.support.annotation.IntDef; +import android.support.annotation.RequiresApi; import com.blankj.utilcode.util.ThreadUtils; import com.blankj.utilcode.util.Utils; @@ -37,6 +39,32 @@ public final class BatteryUtils { int FULL = BatteryManager.BATTERY_STATUS_FULL; } + /** + * Return whether the app is on the device's power whitelist. + * + * @return {@code true}: yes
{@code false}: no + */ + @RequiresApi(api = Build.VERSION_CODES.M) + public static boolean isIgnoringBatteryOptimizations() { + return isIgnoringBatteryOptimizations(Utils.getApp().getPackageName()); + } + + /** + * Return whether the app is on the device's power whitelist. + * + * @return {@code true}: yes
{@code false}: no + */ + @RequiresApi(api = Build.VERSION_CODES.M) + public static boolean isIgnoringBatteryOptimizations(String pkgName) { + try { + PowerManager pm = (PowerManager) Utils.getApp().getSystemService(Context.POWER_SERVICE); + //noinspection ConstantConditions + return pm.isIgnoringBatteryOptimizations(pkgName); + } catch (Exception e) { + return true; + } + } + /** * Register the status of battery changed listener. * diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index a50fef56c8..e8edeb5927 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.5' +implementation 'com.blankj:utilcode:1.30.6' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.5' +implementation 'com.blankj:utilcodex:1.30.6' ``` diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md index 55ad2d880a..63f7a83ba7 100644 --- a/lib/utilcode/README.md +++ b/lib/utilcode/README.md @@ -2,10 +2,10 @@ Gradle: ```groovy -implementation 'com.blankj:utilcode:1.30.5' +implementation 'com.blankj:utilcode:1.30.6' // if u use AndroidX, use the following -implementation 'com.blankj:utilcodex:1.30.5' +implementation 'com.blankj:utilcodex:1.30.6' ``` diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/RegexConstants.java b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/RegexConstants.java index 2c85bf835f..02618da72b 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/constant/RegexConstants.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/constant/RegexConstants.java @@ -16,13 +16,14 @@ public final class RegexConstants { public static final String REGEX_MOBILE_SIMPLE = "^[1]\\d{10}$"; /** * Regex of exact mobile. - *

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, 198

- *

china unicom: 130, 131, 132, 145, 155, 156, 166, 167, 171, 175, 176, 185, 186

- *

china telecom: 133, 153, 162, 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[2567])|(17[01235-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/util/ActivityUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ActivityUtils.java index 5a185d47a1..cf902f085a 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 @@ -44,7 +44,7 @@ private ActivityUtils() { * * @param callbacks The callbacks. */ - public static void addActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) { + public static void addActivityLifecycleCallbacks(@Nullable final Utils.ActivityLifecycleCallbacks callbacks) { UtilsBridge.addActivityLifecycleCallbacks(callbacks); } @@ -54,8 +54,8 @@ public static void addActivityLifecycleCallbacks(final Utils.ActivityLifecycleCa * @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); } @@ -64,7 +64,7 @@ public static void addActivityLifecycleCallbacks(final Activity activity, * * @param callbacks The callbacks. */ - public static void removeActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) { + public static void removeActivityLifecycleCallbacks(@Nullable final Utils.ActivityLifecycleCallbacks callbacks) { UtilsBridge.removeActivityLifecycleCallbacks(callbacks); } @@ -73,7 +73,7 @@ public static void removeActivityLifecycleCallbacks(final Utils.ActivityLifecycl * * @param activity The activity. */ - public static void removeActivityLifecycleCallbacks(final Activity activity) { + public static void removeActivityLifecycleCallbacks(@Nullable final Activity activity) { UtilsBridge.removeActivityLifecycleCallbacks(activity); } @@ -83,8 +83,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); } @@ -94,13 +94,15 @@ 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(@NonNull Context context) { 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; List list = new ArrayList<>(); while (context instanceof ContextWrapper) { @@ -122,7 +124,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 { @@ -1906,6 +1909,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()); } @@ -1916,6 +1920,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 clz) { return getActivityIcon(new ComponentName(Utils.getApp(), clz)); } @@ -1926,6 +1931,7 @@ public static Drawable getActivityIcon(@NonNull final Class * @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 { @@ -1942,6 +1948,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()); } @@ -1952,6 +1959,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 clz) { return getActivityLogo(new ComponentName(Utils.getApp(), clz)); } @@ -1962,6 +1970,7 @@ public static Drawable getActivityLogo(@NonNull final Class * @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 { 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 3a5ec1f12b..1bf781d5d4 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 @@ -1,6 +1,7 @@ package com.blankj.utilcode.util; import android.content.res.Resources; +import android.support.annotation.NonNull; import android.util.DisplayMetrics; import java.lang.reflect.Field; @@ -26,7 +27,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; @@ -35,14 +37,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; @@ -50,7 +54,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); @@ -63,7 +67,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; @@ -91,7 +96,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); 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..d2a08bd812 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,7 @@ package com.blankj.utilcode.util; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import java.lang.annotation.ElementType; @@ -47,14 +48,17 @@ private void registerImpl(Class implClass) { * @param The type. * @return the api */ + @Nullable public static T getApi(@NonNull final Class apiClass) { return getInstance().getApiInner(apiClass); } - public static void register(Class implClass) { + public static void register(@Nullable Class 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 b4884a3442..a8b65dfecf 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 @@ -13,6 +13,7 @@ import android.net.Uri; import android.os.Build; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import java.io.File; @@ -143,8 +144,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; + } } /** @@ -167,7 +174,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; @@ -203,8 +210,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 +225,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; } } @@ -328,6 +333,7 @@ public static void exitApp() { * * @return the application's icon */ + @Nullable public static Drawable getAppIcon() { return getAppIcon(Utils.getApp().getPackageName()); } @@ -338,6 +344,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 { @@ -382,6 +389,7 @@ public static int getAppIconId(final String packageName) { * * @return the application's package name */ + @NonNull public static String getAppPackageName() { return Utils.getApp().getPackageName(); } @@ -391,6 +399,7 @@ public static String getAppPackageName() { * * @return the application's name */ + @NonNull public static String getAppName() { return getAppName(Utils.getApp().getPackageName()); } @@ -401,12 +410,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 ""; @@ -418,6 +428,7 @@ public static String getAppName(final String packageName) { * * @return the application's path */ + @NonNull public static String getAppPath() { return getAppPath(Utils.getApp().getPackageName()); } @@ -428,12 +439,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 ""; @@ -445,6 +457,7 @@ public static String getAppPath(final String packageName) { * * @return the application's version name */ + @NonNull public static String getAppVersionName() { return getAppVersionName(Utils.getApp().getPackageName()); } @@ -455,12 +468,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 ""; @@ -499,6 +513,7 @@ public static int getAppVersionCode(final String packageName) { * * @return the application's signature */ + @Nullable public static Signature[] getAppSignatures() { return getAppSignatures(Utils.getApp().getPackageName()); } @@ -509,6 +524,7 @@ public static Signature[] getAppSignatures() { * @param packageName The name of the package. * @return the application's signature */ + @Nullable public static Signature[] getAppSignatures(final String packageName) { if (UtilsBridge.isSpace(packageName)) return null; try { @@ -541,6 +557,7 @@ public static Signature[] getAppSignatures(final String packageName) { * @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(); @@ -567,6 +584,7 @@ public static Signature[] getAppSignatures(final File file) { * * @return the application's signature for SHA1 value */ + @NonNull public static List getAppSignaturesSHA1() { return getAppSignaturesSHA1(Utils.getApp().getPackageName()); } @@ -577,6 +595,7 @@ public static List getAppSignaturesSHA1() { * @param packageName The name of the package. * @return the application's signature for SHA1 value */ + @NonNull public static List getAppSignaturesSHA1(final String packageName) { return getAppSignaturesHash(packageName, "SHA1"); } @@ -586,6 +605,7 @@ public static List getAppSignaturesSHA1(final String packageName) { * * @return the application's signature for SHA256 value */ + @NonNull public static List getAppSignaturesSHA256() { return getAppSignaturesSHA256(Utils.getApp().getPackageName()); } @@ -596,6 +616,7 @@ public static List getAppSignaturesSHA256() { * @param packageName The name of the package. * @return the application's signature for SHA256 value */ + @NonNull public static List getAppSignaturesSHA256(final String packageName) { return getAppSignaturesHash(packageName, "SHA256"); } @@ -605,6 +626,7 @@ public static List getAppSignaturesSHA256(final String packageName) { * * @return the application's signature for MD5 value */ + @NonNull public static List getAppSignaturesMD5() { return getAppSignaturesMD5(Utils.getApp().getPackageName()); } @@ -615,6 +637,7 @@ public static List getAppSignaturesMD5() { * @param packageName The name of the package. * @return the application's signature for MD5 value */ + @NonNull public static List getAppSignaturesMD5(final String packageName) { return getAppSignaturesHash(packageName, "MD5"); } @@ -670,6 +693,7 @@ private static List getAppSignaturesHash(final String packageName, final * * @return the application's information */ + @Nullable public static AppInfo getAppInfo() { return getAppInfo(Utils.getApp().getPackageName()); } @@ -689,6 +713,7 @@ public static AppInfo getAppInfo() { * @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(); @@ -705,6 +730,7 @@ public static AppInfo getAppInfo(final String packageName) { * * @return the applications' information */ + @NonNull public static List getAppsInfo() { List list = new ArrayList<>(); PackageManager pm = Utils.getApp().getPackageManager(); @@ -723,6 +749,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()); @@ -733,6 +760,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(); @@ -747,13 +775,16 @@ public static AppUtils.AppInfo getApkInfo(final String apkFilePath) { 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, false); + } String name = ai.loadLabel(pm).toString(); Drawable icon = ai.loadIcon(pm); String packagePath = ai.sourceDir; - String versionName = pi.versionName; - int versionCode = pi.versionCode; boolean isSystem = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != 0; return new AppInfo(packageName, name, icon, packagePath, versionName, versionCode, isSystem); } @@ -839,6 +870,7 @@ public AppInfo(String packageName, String name, Drawable icon, String packagePat } @Override + @NonNull public String toString() { return "{" + "\n pkg name: " + getPackageName() + 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..5ab5c431fd 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 @@ -1,5 +1,8 @@ package com.blankj.utilcode.util; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; @@ -30,39 +33,47 @@ private ArrayUtils() { * @param array The array. * @return a new array only of those given elements. */ - @SafeVarargs + @NonNull public static T[] 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 be null * @return the cloned array, null if null input */ - public static T[] 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 if null array inputs. * The type of the new array is the type of the first array. */ - public static T[] 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 be null @@ -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 static T[] 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"] * * - * @param array the array to remove the element from, may not be null + * @param array the array to remove the element from, may be null * @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 is null. - * @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 static List 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 c) { + public static void sort(@Nullable T[] array, Comparator 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 0092763b12..90acac5882 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 @@ -194,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; @@ -349,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 ? @@ -374,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( @@ -402,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); 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..0a3dc27632 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 @@ -105,7 +105,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 0eb9ec86fa..c06f86fae8 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 @@ -1,5 +1,7 @@ package com.blankj.utilcode.util; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import java.lang.annotation.ElementType; @@ -61,27 +63,27 @@ private void registerBus(String tag, 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); } @@ -102,7 +104,7 @@ 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(); String className = aClass.getName(); 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..7a1a1f199d 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 @@ -4,6 +4,7 @@ import android.graphics.drawable.Drawable; import android.os.Parcelable; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import org.json.JSONArray; import org.json.JSONObject; @@ -27,7 +28,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 +38,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 +49,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 +70,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 +84,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 +95,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 +116,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 +130,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 +142,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 +164,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 +179,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 +190,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 +211,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 +226,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 +237,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 +258,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 +272,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 +283,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 +304,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 +318,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 +329,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 +357,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) { return getParcelable(key, creator, defaultValue, getDefaultCacheDiskUtils()); } @@ -370,7 +371,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 +382,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 +403,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 +456,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 +470,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 +496,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 +513,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 +527,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 +553,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 +570,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 +584,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 +610,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 +628,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 +642,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 +668,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 +686,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 +700,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 +726,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 +743,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 +757,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 +783,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 +800,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 +814,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 +847,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 +864,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 +878,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 +904,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 +950,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/CacheDoubleUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/CacheDoubleUtils.java index c800423c78..1cc8324990 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 @@ -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 @@ public T 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/FragmentUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/FragmentUtils.java index 3e56907eb2..8ddc4344a4 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 @@ -1525,6 +1525,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/ImageUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ImageUtils.java index 242b9dcfd5..7df105a3bc 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 @@ -40,6 +40,8 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -85,7 +87,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); @@ -98,7 +100,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); @@ -110,7 +112,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) { @@ -142,7 +145,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); } @@ -152,7 +155,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)); } @@ -340,7 +343,18 @@ public static Bitmap getBitmap(final byte[] data, * @return bitmap */ public static Bitmap getBitmap(@DrawableRes final int resId) { - return BitmapFactory.decodeResource(Utils.getApp().getResources(), 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(), + Bitmap.Config.ARGB_8888); + canvas.setBitmap(bitmap); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + drawable.draw(canvas); + return bitmap; } /** @@ -1753,24 +1767,87 @@ public static boolean save(final Bitmap src, @Nullable public static File save2Album(final Bitmap src, final CompressFormat format) { - return save2Album(src, format, 100, false); + 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, format, 100, 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 @@ -1780,13 +1857,15 @@ public static File save2Album(final Bitmap src, */ @Nullable public static File save2Album(final Bitmap src, + final String dirName, final CompressFormat format, final int quality) { - return save2Album(src, format, quality, false); + 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 @@ -1797,9 +1876,11 @@ public static File save2Album(final Bitmap src, */ @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) { @@ -1808,7 +1889,7 @@ public static File save2Album(final Bitmap src, return null; } File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); - File destFile = new File(picDir, Utils.getApp().getPackageName() + "/" + fileName); + File destFile = new File(picDir, safeDirName + "/" + fileName); if (!save(src, destFile, format, quality, recycle)) { return null; } @@ -1824,7 +1905,7 @@ public static File save2Album(final Bitmap src, } else { contentUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI; } - contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/" + Utils.getApp().getPackageName()); + 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) { 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 2364db719c..4a821458fa 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,6 +8,7 @@ import android.os.Bundle; import android.provider.MediaStore; import android.provider.Settings; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.RequiresPermission; import android.support.v4.content.FileProvider; @@ -402,8 +403,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); } @@ -415,8 +416,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); } @@ -427,8 +428,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); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/PhoneUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/PhoneUtils.java index 1e5e2982a3..972d804e16 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/PhoneUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/PhoneUtils.java @@ -3,6 +3,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; +import android.support.annotation.NonNull; import android.support.annotation.RequiresPermission; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -288,7 +289,7 @@ public static String getSimOperatorByMnc() { * * @param phoneNumber The phone number. */ - public static void dial(final String phoneNumber) { + public static void dial(@NonNull final String phoneNumber) { Utils.getApp().startActivity(UtilsBridge.getDialIntent(phoneNumber)); } @@ -299,7 +300,7 @@ public static void dial(final String phoneNumber) { * @param phoneNumber The phone number. */ @RequiresPermission(CALL_PHONE) - public static void call(final String phoneNumber) { + public static void call(@NonNull final String phoneNumber) { Utils.getApp().startActivity(UtilsBridge.getCallIntent(phoneNumber)); } @@ -309,7 +310,7 @@ public static void call(final String phoneNumber) { * @param phoneNumber The phone number. * @param content The content. */ - public static void sendSms(final String phoneNumber, final String content) { + public static void sendSms(@NonNull final String phoneNumber, final String content) { Utils.getApp().startActivity(UtilsBridge.getSendSmsIntent(phoneNumber, content)); } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/RomUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/RomUtils.java index 90f2255cf1..49e1cf6fcf 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/RomUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/RomUtils.java @@ -38,7 +38,7 @@ public final class RomUtils { private static final String[] ROM_SAMSUNG = {"samsung"}; private static final String[] ROM_MEIZU = {"meizu"}; private static final String[] ROM_LENOVO = {"lenovo"}; - private static final String[] ROM_SMARTISAN = {"smartisan"}; + private static final String[] ROM_SMARTISAN = {"smartisan", "deltainno"}; private static final String[] ROM_HTC = {"htc"}; private static final String[] ROM_SONY = {"sony"}; private static final String[] ROM_GIONEE = {"gionee", "amigo"}; diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java index fbc3ff02ff..ca14204dfc 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/SnackbarUtils.java @@ -47,7 +47,7 @@ public final class SnackbarUtils { private static final int COLOR_ERROR = 0xFFFF0000; private static final int COLOR_MESSAGE = 0xFFFFFFFF; - private static WeakReference sReference; + private static WeakReference sWeakSnackbar; private View view; private CharSequence message; @@ -223,11 +223,11 @@ public Snackbar show(boolean isShowTop) { spannableString.setSpan( colorSpan, 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE ); - sReference = new WeakReference<>(Snackbar.make(view, spannableString, duration)); + sWeakSnackbar = new WeakReference<>(Snackbar.make(view, spannableString, duration)); } else { - sReference = new WeakReference<>(Snackbar.make(view, message, duration)); + sWeakSnackbar = new WeakReference<>(Snackbar.make(view, message, duration)); } - final Snackbar snackbar = sReference.get(); + final Snackbar snackbar = sWeakSnackbar.get(); final Snackbar.SnackbarLayout snackbarView = (Snackbar.SnackbarLayout) snackbar.getView(); if (isShowTop) { for (int i = 0; i < snackbarView.getChildCount(); i++) { @@ -316,9 +316,9 @@ public void showError(boolean isShowTop) { * Dismiss the snackbar. */ public static void dismiss() { - if (sReference != null && sReference.get() != null) { - sReference.get().dismiss(); - sReference = null; + if (sWeakSnackbar != null && sWeakSnackbar.get() != null) { + sWeakSnackbar.get().dismiss(); + sWeakSnackbar = null; } } @@ -328,7 +328,7 @@ public static void dismiss() { * @return the view of snackbar */ public static View getView() { - Snackbar snackbar = sReference.get(); + Snackbar snackbar = sWeakSnackbar.get(); if (snackbar == null) return null; return snackbar.getView(); } diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/SpanUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/SpanUtils.java index 86141a8d56..f8eb9465bd 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/SpanUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/SpanUtils.java @@ -514,9 +514,7 @@ public SpanUtils setVerticalAlign(@Align final int align) { * @return the single {@link SpanUtils} instance */ public SpanUtils setClickSpan(@NonNull final ClickableSpan clickSpan) { - if (mTextView != null && mTextView.getMovementMethod() == null) { - mTextView.setMovementMethod(LinkMovementMethod.getInstance()); - } + setMovementMethodIfNeed(); this.clickSpan = clickSpan; return this; } @@ -533,9 +531,7 @@ public SpanUtils setClickSpan(@NonNull final ClickableSpan clickSpan) { public SpanUtils setClickSpan(@ColorInt final int color, final boolean underlineText, final View.OnClickListener listener) { - if (mTextView != null && mTextView.getMovementMethod() == null) { - mTextView.setMovementMethod(LinkMovementMethod.getInstance()); - } + setMovementMethodIfNeed(); this.clickSpan = new ClickableSpan() { @Override @@ -562,11 +558,15 @@ public void onClick(@NonNull View widget) { * @return the single {@link SpanUtils} instance */ public SpanUtils setUrl(@NonNull final String url) { + setMovementMethodIfNeed(); + this.url = url; + return this; + } + + private void setMovementMethodIfNeed() { if (mTextView != null && mTextView.getMovementMethod() == null) { mTextView.setMovementMethod(LinkMovementMethod.getInstance()); } - this.url = url; - return this; } /** diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java index 28efede8d4..f218ae5567 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/StringUtils.java @@ -2,6 +2,7 @@ import android.content.res.Resources; import android.support.annotation.ArrayRes; +import android.support.annotation.Nullable; import android.support.annotation.StringRes; import java.util.IllegalFormatException; @@ -245,7 +246,7 @@ public static String[] getStringArray(@ArrayRes int id) { * @param args The args. * @return a formatted string. */ - public static String format(String str, Object... args) { + public static String format(@Nullable String str, Object... args) { String text = str; if (text != null) { if (args != null && args.length > 0) { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ThreadUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ThreadUtils.java index b99dc4d21f..96830dd89f 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ThreadUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ThreadUtils.java @@ -1216,6 +1216,7 @@ public void run() { if (!isDone() && mTimeoutListener != null) { timeout(); mTimeoutListener.onTimeout(); + onDone(); } } }, mTimeoutMillis); @@ -1287,7 +1288,6 @@ private void timeout() { if (runner != null) { runner.interrupt(); } - onDone(); } @@ -1362,6 +1362,18 @@ public T getValue() { } return mValue; } + + public T getValue(long timeout, TimeUnit unit, T defaultValue) { + if (!mFlag.get()) { + try { + mLatch.await(timeout, unit); + } catch (InterruptedException e) { + e.printStackTrace(); + return defaultValue; + } + } + return mValue; + } } private static Executor getGlobalDeliver() { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java index 69bce2594b..d08f2923bc 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ToastUtils.java @@ -38,6 +38,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.lang.reflect.Field; /** @@ -63,7 +64,7 @@ public final class ToastUtils { private static final String NOTHING = "toast nothing"; private static final ToastUtils DEFAULT_MAKER = make(); - private static IToast iToast; + private static WeakReference sWeakToast; private String mMode; private int mGravity = -1; @@ -82,6 +83,7 @@ public final class ToastUtils { * * @return the single {@link ToastUtils} instance */ + @NonNull public static ToastUtils make() { return new ToastUtils(); } @@ -90,6 +92,7 @@ public static ToastUtils make() { * @param mode The mode. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setMode(@MODE String mode) { mMode = mode; return this; @@ -103,6 +106,7 @@ public final ToastUtils setMode(@MODE String mode) { * @param yOffset Y-axis offset, in pixel. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setGravity(final int gravity, final int xOffset, final int yOffset) { mGravity = gravity; mXOffset = xOffset; @@ -116,6 +120,7 @@ public final ToastUtils setGravity(final int gravity, final int xOffset, final i * @param backgroundColor The color of background. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setBgColor(@ColorInt final int backgroundColor) { mBgColor = backgroundColor; return this; @@ -127,6 +132,7 @@ public final ToastUtils setBgColor(@ColorInt final int backgroundColor) { * @param bgResource The resource of background. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setBgResource(@DrawableRes final int bgResource) { mBgResource = bgResource; return this; @@ -138,6 +144,7 @@ public final ToastUtils setBgResource(@DrawableRes final int bgResource) { * @param msgColor The text color of toast. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setTextColor(@ColorInt final int msgColor) { mTextColor = msgColor; return this; @@ -149,6 +156,7 @@ public final ToastUtils setTextColor(@ColorInt final int msgColor) { * @param textSize The text size of toast. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setTextSize(final int textSize) { mTextSize = textSize; return this; @@ -159,6 +167,7 @@ public final ToastUtils setTextSize(final int textSize) { * * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setDurationIsLong(boolean isLong) { this.isLong = isLong; return this; @@ -170,6 +179,7 @@ public final ToastUtils setDurationIsLong(boolean isLong) { * @param resId The left icon resource identifier. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setLeftIcon(@DrawableRes int resId) { return setLeftIcon(ContextCompat.getDrawable(Utils.getApp(), resId)); } @@ -180,7 +190,8 @@ public final ToastUtils setLeftIcon(@DrawableRes int resId) { * @param drawable The left icon drawable. * @return the single {@link ToastUtils} instance */ - public final ToastUtils setLeftIcon(Drawable drawable) { + @NonNull + public final ToastUtils setLeftIcon(@Nullable Drawable drawable) { mIcons[0] = drawable; return this; } @@ -191,6 +202,7 @@ public final ToastUtils setLeftIcon(Drawable drawable) { * @param resId The top icon resource identifier. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setTopIcon(@DrawableRes int resId) { return setTopIcon(ContextCompat.getDrawable(Utils.getApp(), resId)); } @@ -201,7 +213,8 @@ public final ToastUtils setTopIcon(@DrawableRes int resId) { * @param drawable The top icon drawable. * @return the single {@link ToastUtils} instance */ - public final ToastUtils setTopIcon(Drawable drawable) { + @NonNull + public final ToastUtils setTopIcon(@Nullable Drawable drawable) { mIcons[1] = drawable; return this; } @@ -212,6 +225,7 @@ public final ToastUtils setTopIcon(Drawable drawable) { * @param resId The right icon resource identifier. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setRightIcon(@DrawableRes int resId) { return setRightIcon(ContextCompat.getDrawable(Utils.getApp(), resId)); } @@ -222,7 +236,8 @@ public final ToastUtils setRightIcon(@DrawableRes int resId) { * @param drawable The right icon drawable. * @return the single {@link ToastUtils} instance */ - public final ToastUtils setRightIcon(Drawable drawable) { + @NonNull + public final ToastUtils setRightIcon(@Nullable Drawable drawable) { mIcons[2] = drawable; return this; } @@ -233,6 +248,7 @@ public final ToastUtils setRightIcon(Drawable drawable) { * @param resId The bottom icon resource identifier. * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setBottomIcon(int resId) { return setBottomIcon(ContextCompat.getDrawable(Utils.getApp(), resId)); } @@ -243,7 +259,8 @@ public final ToastUtils setBottomIcon(int resId) { * @param drawable The bottom icon drawable. * @return the single {@link ToastUtils} instance */ - public final ToastUtils setBottomIcon(Drawable drawable) { + @NonNull + public final ToastUtils setBottomIcon(@Nullable Drawable drawable) { mIcons[3] = drawable; return this; } @@ -253,6 +270,7 @@ public final ToastUtils setBottomIcon(Drawable drawable) { * * @return the single {@link ToastUtils} instance */ + @NonNull public final ToastUtils setNotUseSystemToast() { isNotUseSystemToast = true; return this; @@ -263,6 +281,7 @@ public final ToastUtils setNotUseSystemToast() { * * @return the default {@link ToastUtils} instance */ + @NonNull public static ToastUtils getDefaultMaker() { return DEFAULT_MAKER; } @@ -272,7 +291,7 @@ public static ToastUtils getDefaultMaker() { * * @param text The text. */ - public final void show(final CharSequence text) { + public final void show(@Nullable final CharSequence text) { show(text, getDuration(), this); } @@ -301,14 +320,14 @@ public final void show(@StringRes final int resId, final Object... args) { * @param format The format. * @param args The args. */ - public final void show(final String format, final Object... args) { + public final void show(@Nullable final String format, final Object... args) { show(UtilsBridge.format(format, args), getDuration(), this); } /** * Show custom toast. */ - public final void show(final View view) { + public final void show(@NonNull final View view) { show(view, getDuration(), this); } @@ -359,7 +378,7 @@ private View tryApplyUtilsToastView(final CharSequence text) { * * @param text The text. */ - public static void showShort(final CharSequence text) { + public static void showShort(@Nullable final CharSequence text) { show(text, Toast.LENGTH_SHORT, DEFAULT_MAKER); } @@ -388,7 +407,7 @@ public static void showShort(@StringRes final int resId, final Object... args) { * @param format The format. * @param args The args. */ - public static void showShort(final String format, final Object... args) { + public static void showShort(@Nullable final String format, final Object... args) { show(UtilsBridge.format(format, args), Toast.LENGTH_SHORT, DEFAULT_MAKER); } @@ -397,7 +416,7 @@ public static void showShort(final String format, final Object... args) { * * @param text The text. */ - public static void showLong(final CharSequence text) { + public static void showLong(@Nullable final CharSequence text) { show(text, Toast.LENGTH_LONG, DEFAULT_MAKER); } @@ -426,7 +445,7 @@ public static void showLong(@StringRes final int resId, final Object... args) { * @param format The format. * @param args The args. */ - public static void showLong(final String format, final Object... args) { + public static void showLong(@Nullable final String format, final Object... args) { show(UtilsBridge.format(format, args), Toast.LENGTH_LONG, DEFAULT_MAKER); } @@ -434,26 +453,38 @@ public static void showLong(final String format, final Object... args) { * Cancel the toast. */ public static void cancel() { - if (iToast != null) { - iToast.cancel(); - iToast = null; - } + UtilsBridge.runOnUiThread(new Runnable() { + @Override + public void run() { + if (sWeakToast != null) { + final IToast iToast = ToastUtils.sWeakToast.get(); + if (iToast != null) { + iToast.cancel(); + } + sWeakToast = null; + } + } + }); } - private static void show(final CharSequence text, final int duration, final ToastUtils utils) { + private static void show(@Nullable final CharSequence text, final int duration, final ToastUtils utils) { show(null, getToastFriendlyText(text), duration, utils); } - private static void show(final View view, final int duration, final ToastUtils utils) { + private static void show(@NonNull final View view, final int duration, final ToastUtils utils) { show(view, null, duration, utils); } - private static void show(@Nullable final View view, final CharSequence text, final int duration, final ToastUtils utils) { + private static void show(@Nullable final View view, + @Nullable final CharSequence text, + final int duration, + @NonNull final ToastUtils utils) { UtilsBridge.runOnUiThread(new Runnable() { @Override public void run() { cancel(); - iToast = newToast(utils); + IToast iToast = newToast(utils); + ToastUtils.sWeakToast = new WeakReference<>(iToast); if (view != null) { iToast.setToastView(view); } else { @@ -491,9 +522,9 @@ private static IToast newToast(ToastUtils toastUtils) { return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_TOAST); } else if (UtilsBridge.isGrantedDrawOverlays()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else { - new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_PHONE); + return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_PHONE); } } return new ActivityToast(toastUtils); @@ -553,11 +584,17 @@ static final class WindowManagerToast extends AbsToast { private WindowManager.LayoutParams mParams; - private Utils.ActivityLifecycleCallbacks mActivityLifecycleCallbacks; - WindowManagerToast(ToastUtils toastUtils, int type) { super(toastUtils); mParams = new WindowManager.LayoutParams(); + mWM = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE); + mParams.type = type; + } + + WindowManagerToast(ToastUtils toastUtils, WindowManager wm, int type) { + super(toastUtils); + mParams = new WindowManager.LayoutParams(); + mWM = wm; mParams.type = type; } @@ -587,7 +624,6 @@ public void show(final int duration) { mParams.horizontalMargin = mToast.getHorizontalMargin(); mParams.verticalMargin = mToast.getVerticalMargin(); - mWM = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE); try { if (mWM != null) { mWM.addView(mToastView, mParams); @@ -619,6 +655,7 @@ static final class ActivityToast extends AbsToast { private static int sShowingIndex = 0; private Utils.ActivityLifecycleCallbacks mActivityLifecycleCallbacks; + private IToast iToast; ActivityToast(ToastUtils toastUtils) { super(toastUtils); @@ -629,7 +666,7 @@ public void show(int duration) { if (mToast == null) return; if (!UtilsBridge.isAppForeground()) { // try to use system toast - showSystemToast(duration); + iToast = showSystemToast(duration); return; } boolean hasAliveActivity = false; @@ -637,8 +674,12 @@ public void show(int duration) { if (!UtilsBridge.isActivityAlive(activity)) { continue; } - hasAliveActivity = true; - showWithActivity(activity, sShowingIndex, true); + if (!hasAliveActivity) { + hasAliveActivity = true; + iToast = showWithActivityWindow(activity, duration); + } else { + showWithActivityView(activity, sShowingIndex, true); + } } if (hasAliveActivity) { registerLifecycleCallback(); @@ -652,7 +693,7 @@ public void run() { ++sShowingIndex; } else { // try to use system toast - showSystemToast(duration); + iToast = showSystemToast(duration); } } @@ -676,16 +717,29 @@ public void cancel() { } } } + if (iToast != null) { + iToast.cancel(); + iToast = null; + } super.cancel(); } - private void showSystemToast(int duration) { + private IToast showSystemToast(int duration) { SystemToast systemToast = new SystemToast(mToastUtils); systemToast.mToast = mToast; systemToast.show(duration); + return systemToast; } - private void showWithActivity(final Activity activity, final int index, boolean useAnim) { + private IToast showWithActivityWindow(Activity activity, int duration) { + WindowManagerToast wmToast = new WindowManagerToast(mToastUtils, activity.getWindowManager(), WindowManager.LayoutParams.LAST_APPLICATION_WINDOW); + wmToast.mToastView = getToastViewSnapshot(-1); + wmToast.mToast = mToast; + wmToast.show(duration); + return wmToast; + } + + private void showWithActivityView(final Activity activity, final int index, boolean useAnim) { final Window window = activity.getWindow(); if (window != null) { final ViewGroup decorView = (ViewGroup) window.getDecorView(); @@ -694,6 +748,7 @@ private void showWithActivity(final Activity activity, final int index, boolean ); lp.gravity = mToast.getGravity(); lp.bottomMargin = mToast.getYOffset() + UtilsBridge.getNavBarHeight(); + lp.topMargin = mToast.getYOffset() + UtilsBridge.getStatusBarHeight(); lp.leftMargin = mToast.getXOffset(); View toastViewSnapshot = getToastViewSnapshot(index); if (useAnim) { @@ -704,21 +759,13 @@ private void showWithActivity(final Activity activity, final int index, boolean } } - private View getToastViewSnapshot(final int index) { - Bitmap bitmap = UtilsBridge.view2Bitmap(mToastView); - ImageView toastIv = new ImageView(Utils.getApp()); - toastIv.setTag(TAG_TOAST + index); - toastIv.setImageBitmap(bitmap); - return toastIv; - } - private void registerLifecycleCallback() { final int index = sShowingIndex; mActivityLifecycleCallbacks = new Utils.ActivityLifecycleCallbacks() { @Override public void onActivityCreated(@NonNull Activity activity) { if (isShowing()) { - showWithActivity(activity, index, false); + showWithActivityView(activity, index, false); } } }; @@ -761,6 +808,7 @@ public void setToastView(CharSequence text) { View utilsToastView = mToastUtils.tryApplyUtilsToastView(text); if (utilsToastView != null) { setToastView(utilsToastView); + processRtlIfNeed(); return; } @@ -778,9 +826,16 @@ public void setToastView(CharSequence text) { messageTv.setTextSize(mToastUtils.mTextSize); } setBg(messageTv); + processRtlIfNeed(); } - protected void setBg(final TextView msgTv) { + private void processRtlIfNeed() { + if (UtilsBridge.isLayoutRtl()) { + setToastView(getToastViewSnapshot(-1)); + } + } + + private void setBg(final TextView msgTv) { if (mToastUtils.mBgResource != -1) { mToastView.setBackgroundResource(mToastUtils.mBgResource); msgTv.setBackgroundColor(Color.TRANSPARENT); @@ -809,6 +864,14 @@ public void cancel() { mToast = null; mToastView = null; } + + View getToastViewSnapshot(final int index) { + Bitmap bitmap = UtilsBridge.view2Bitmap(mToastView); + ImageView toastIv = new ImageView(Utils.getApp()); + toastIv.setTag(TAG_TOAST + index); + toastIv.setImageBitmap(bitmap); + return toastIv; + } } interface IToast { diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java index 272eddcb45..28414efd78 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsActivityLifecycleImpl.java @@ -201,6 +201,9 @@ public void onActivityPreCreated(@NonNull Activity activity, @Nullable Bundle sa @Override public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) { + if (mActivityList.size() == 0) { + postStatus(activity, true); + } LanguageUtils.applyLanguage(activity); setAnimatorsEnabled(); setTopActivity(activity); diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java index 5361fdc1de..e920b53635 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UtilsBridge.java @@ -12,6 +12,7 @@ import android.os.Parcelable; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.support.annotation.RequiresPermission; import android.support.annotation.StringRes; @@ -535,7 +536,7 @@ static String getString(@StringRes int id, Object... formatArgs) { return StringUtils.getString(id, formatArgs); } - static String format(String str, Object... args) { + static String format(@Nullable String str, Object... args) { return StringUtils.format(str, args); } @@ -606,6 +607,10 @@ static View layoutId2View(@LayoutRes final int layoutId) { return ViewUtils.layoutId2View(layoutId); } + static boolean isLayoutRtl() { + return ViewUtils.isLayoutRtl(); + } + /////////////////////////////////////////////////////////////////////////// // Common diff --git a/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml b/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml index ce405066c0..ed731a2299 100644 --- a/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml +++ b/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml @@ -1,9 +1,5 @@ - - diff --git a/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/BaseContentView.java b/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/BaseContentView.java index 246c011492..0af63e0fa8 100644 --- a/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/BaseContentView.java +++ b/lib/utildebug/src/main/java/com/blankj/utildebug/base/view/BaseContentView.java @@ -10,6 +10,8 @@ import com.blankj.utildebug.base.view.listener.OnBackListener; import com.blankj.utildebug.base.view.listener.OnRefreshListener; +import java.util.Collections; + /** *
  *     author: blankj

From 66a4c0488ca6da273098058d70dabb0fe9b9bd8d Mon Sep 17 00:00:00 2001
From: Blankj 
Date: Mon, 22 Feb 2021 00:07:51 +0800
Subject: [PATCH 28/61] see 02/22 log

---
 .../blankj/subutil/util/CoordinateUtils.java  | 28 +++++++++++
 .../com/blankj/utilcode/util/IntentUtils.java |  4 +-
 .../com/blankj/utilcode/util/ScreenUtils.java | 46 ++++++++-----------
 3 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java b/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
index ee6d78a118..c205a52a75 100644
--- a/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
+++ b/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
@@ -121,6 +121,34 @@ public static double[] wgs84ToBd09(double lng, double lat) {
         return gcj02ToBd09(gcj[0], gcj[1]);
     }
 
+    /**
+     * Mercator 坐标转 WGS84 坐标
+     *
+     * @param lng Mercator 坐标经度
+     * @param lat Mercator 坐标纬度
+     * @return WGS84 坐标:[经度,纬度]
+     */
+    public static double[] mercatorToWGS84(double lng, double lat) {
+        double x = lng / 20037508.34d * 180.;
+        double y = lat / 20037508.34d * 180.;
+        y = 180 / PI * (2 * Math.atan(Math.exp(y * PI / 180.0)) - PI / 2);
+        return new double[]{x, y};
+    }
+
+    /**
+     * WGS84 坐标转 Mercator 坐标
+     *
+     * @param lng WGS84 坐标经度
+     * @param lat WGS84 坐标纬度
+     * @return Mercator 坐标:[经度,纬度]
+     */
+    public static double[] wgs84ToMercator(double lng, double lat) {
+        double x = lng * 20037508.34D / 180.0;
+        double y = Math.log(Math.tan((90.0 + lat) * PI / 360.0)) / (PI / 180.);
+        y = y * 20037508.34D / 180.0;
+        return new double[]{x, y};
+    }
+
     private static double transformLat(double lng, double lat) {
         double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
         ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
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 4a821458fa..fccddd8d35 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
@@ -389,9 +389,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);
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
index cb742b7a7d..623e15518b 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/ScreenUtils.java
@@ -112,39 +112,34 @@ public static float getScreenDensity() {
     public static int getScreenDensityDpi() {
         return Resources.getSystem().getDisplayMetrics().densityDpi;
     }
-    
-    
-    
-    
+
     /**
-     * Return X (width) of the screen expressed as dots-per-inch.
+     * Return the exact physical pixels per inch of the screen in the Y dimension.
      *
-     * @return the width of screen density expressed as dots-per-inch
+     * @return the exact physical pixels per inch of the screen in the Y dimension
      */
-    public static int getScreenXDpi() {
+    public static float getScreenXDpi() {
         return Resources.getSystem().getDisplayMetrics().xdpi;
     }
-    
+
     /**
-     * Return Y (height) of the screen expressed as dots-per-inch.
+     * Return the exact physical pixels per inch of the screen in the Y dimension.
      *
-     * @return the height of screen density expressed as dots-per-inch
+     * @return the exact physical pixels per inch of the screen in the Y dimension
      */
-    public static int getScreenYDpi() {
+    public static float getScreenYDpi() {
         return Resources.getSystem().getDisplayMetrics().ydpi;
     }
-    
-   
-    
+
     /**
      * Return the distance between the given View's X (start point of View's width) and the screen width.
      *
      * @return the distance between the given View's X (start point of View's width) and the screen width.
      */
-    public float calculateDistanceByX(View view) {
-        int[] point = new int[0];
+    public int calculateDistanceByX(View view) {
+        int[] point = new int[2];
         view.getLocationOnScreen(point);
-        return (getScreenWidth() - point[0]).toFloat();
+        return getScreenWidth() - point[0];
     }
 
     /**
@@ -152,10 +147,10 @@ public float calculateDistanceByX(View view) {
      *
      * @return the distance between the given View's Y (start point of View's height) and the screen height.
      */
-    public float calculateDistanceByY(View view) {
-        int[] point = new int[0];
+    public int calculateDistanceByY(View view) {
+        int[] point = new int[2];
         view.getLocationOnScreen(point);
-        return (getScreenHeight() - point[1]).toFloat();
+        return getScreenHeight() - point[1];
     }
 
     /**
@@ -163,23 +158,22 @@ public float calculateDistanceByY(View view) {
      *
      * @return X coordinate of the given View on the screen.
      */
-    public int getViewX(View view){
-        int[] point = new int[0];
+    public int getViewX(View view) {
+        int[] point = new int[2];
         view.getLocationOnScreen(point);
         return point[0];
     }
-    
+
     /**
      * Return the Y coordinate of the given View on the screen.
      *
      * @return Y coordinate of the given View on the screen.
      */
-    public int getViewY(View view){
-        int[] point = new int[0];
+    public int getViewY(View view) {
+        int[] point = new int[2];
         view.getLocationOnScreen(point);
         return point[1];
     }
-    
 
     /**
      * Set full screen.

From f14b404543d17cdba6680a78a15afdf7570a9248 Mon Sep 17 00:00:00 2001
From: jobs_xie 
Date: Thu, 22 Apr 2021 10:46:19 +0800
Subject: [PATCH 29/61] Fix: IllegalStateException: message is already in use

---
 .../src/main/java/com/blankj/utilcode/util/MessengerUtils.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 a764eb50b6..d1d4669dbe 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
@@ -320,7 +320,7 @@ private void sendMsg2Client(final Message msg) {
             for (Messenger client : mClientMap.values()) {
                 try {
                     if (client != null) {
-                        client.send(msg);
+                        client.send(Message.obtain(msg));
                     }
                 } catch (RemoteException e) {
                     e.printStackTrace();

From e04bfdf9eff1cc82788a0255d38bdcb9f08180cc Mon Sep 17 00:00:00 2001
From: jobs_xie 
Date: Thu, 22 Apr 2021 10:58:44 +0800
Subject: [PATCH 30/61] Fix: IllegalStateException: message is already in use

---
 .../main/java/com/blankj/utilcode/util/MessengerUtils.java    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

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 d1d4669dbe..61aa8e2543 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
@@ -317,15 +317,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(Message.obtain(msg));
+                        client.send(obtain);
                     }
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
             }
+            obtain.recycle(); //Recycled copy
         }
 
         private void consumeServerProcessCallback(final Message msg) {

From ab073b7a4d856771822c08fbdf2a13f300420ce1 Mon Sep 17 00:00:00 2001
From: xiexin52k <517436384@qq.com>
Date: Thu, 22 Apr 2021 14:28:21 +0800
Subject: [PATCH 31/61] Update MessengerUtils.java

---
 .../src/main/java/com/blankj/utilcode/util/MessengerUtils.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 61aa8e2543..71af539ab7 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
@@ -321,7 +321,7 @@ private void sendMsg2Client(final Message msg) {
             for (Messenger client : mClientMap.values()) {
                 try {
                     if (client != null) {
-                        client.send(obtain);
+                        client.send(Message.obtain(obtain));
                     }
                 } catch (RemoteException e) {
                     e.printStackTrace();

From 20290bb808058d92cf52a2632fc463faccc10ff6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A9=AC=E6=AD=87=E5=B0=94?= 
Date: Wed, 5 May 2021 02:51:15 +1000
Subject: [PATCH 32/61] Added 2 very useful methods

1. isFirstTimeInstall():
If you want to know whether this is the first time installation of this app in this device.
2. isAppUpgraded():
If you want to know whether the current version was installed over a previous version (update/upgrade) or if it is freshly installed (clean install).

Code:
/**
     * 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(this.getAppPackageName(), 0).firstInstallTime;
            Long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(this.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(this.getAppPackageName(), 0).firstInstallTime;
            Long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(this.getAppPackageName(), 0).lastUpdateTime;
            return firstInstallTime != lastUpdateTime;
        } catch (Exception e) {
            return false;
        }
    }
---
 .../com/blankj/utilcode/util/AppUtils.java    | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

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 a8b65dfecf..1cc9112b16 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
@@ -384,6 +384,38 @@ 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(this.getAppPackageName(), 0).firstInstallTime;
+            Long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(this.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(this.getAppPackageName(), 0).firstInstallTime;
+            Long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(this.getAppPackageName(), 0).lastUpdateTime;
+            return firstInstallTime != lastUpdateTime;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+    
+   
     /**
      * Return the application's package name.
      *

From cbea6b40658e04ee923c2e4c1d5fad0e18bae5ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A9=AC=E6=AD=87=E5=B0=94?= 
Date: Tue, 4 May 2021 18:56:24 +0200
Subject: [PATCH 33/61] Added yet another 2 very useful methods

1. isBehindProxy():
Returns true if device is connecting to the internet via a proxy, works for both Wi-Fi and Mobile Data.
2. isUsingVPN():
Returns true if device is connecting to the internet via a VPN.
---
 .../blankj/utilcode/util/NetworkUtils.java    | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

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 8f874dbf38..37104b1b43 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
@@ -261,6 +261,34 @@ public static boolean getMobileDataEnabled() {
         }
         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.

From ebc64cd35122d1cba80822dd5942900d7fa507ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A9=AC=E6=AD=87=E5=B0=94?= 
Date: Mon, 10 May 2021 10:11:14 +0700
Subject: [PATCH 34/61] Added 4 useful methods

/**
     * Returns the domain part of a given Email address
     *
     * @param email The Email address. E.g Returns "protonmail.com" from the given Email "johnsmith@protonmail.com".
     * @return the domain part of a given Email address.
     */
    public static String extractEmailProvider(String email) {
        return email.substring(email.lastIndexOf("@") + 1);
    }

    /**
     * Returns the username part of a given Email address. E.g. Returns "johnsmith" from the given Email "johnsmith@protonmail.com".
     *
     * @param email The Email address.
     * @return the username part of a given Email address.
     */
    public static String extractEmailUsername(String email) {
        return email.substring(0, email.lastIndexOf("@"));
    }


    /**
     * Return whether a given Email address is on a specified Email provider. E.g. "johnsmith@protonmail.com" and "gmail.com" will return false.
     *
     * @param email The Email address.
     * @param emailProvider The Email provider to testify against.
     * @return {@code true}: yes
{@code false}: no */ public static boolean isFromEmailProvider(String email, String emailProvider) { return extractEmailProvider(email).equalsIgnoreCase(emailProvider); } /** * Return whether a given Email address is on any of the specified Email providers list (array). E.g. Useful if you pass it a list of real Email provider services and check if the Email is a disposable Email or a real one. * * @param email The Email address. * @param emailProviders The list of Email providers to testify against. * @return {@code true}: yes
{@code false}: no */ public static boolean isFromAnyOfEmailProviders(String email, String[] emailProviders) { return com.blankj.utilcode.util.ArrayUtils.contains(emailProviders, extractEmailProvider(email)); } --- .../com/blankj/utilcode/util/RegexUtils.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/RegexUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/RegexUtils.java index ae90e4ea5e..624a93511c 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/RegexUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/RegexUtils.java @@ -40,6 +40,54 @@ public static boolean isMobileSimple(final CharSequence input) { return isMatch(RegexConstants.REGEX_MOBILE_SIMPLE, input); } + + /** + * Returns the domain part of a given Email address + * + * @param email The Email address. E.g Returns "protonmail.com" from the given Email "johnsmith@protonmail.com". + * @return the domain part of a given Email address. + */ + public static String extractEmailProvider(String email) { + return email.substring(email.lastIndexOf("@") + 1); + } + + /** + * Returns the username part of a given Email address. E.g. Returns "johnsmith" from the given Email "johnsmith@protonmail.com". + * + * @param email The Email address. + * @return the username part of a given Email address. + */ + public static String extractEmailUsername(String email) { + return email.substring(0, email.lastIndexOf("@")); + } + + + /** + * Return whether a given Email address is on a specified Email provider. E.g. "johnsmith@protonmail.com" and "gmail.com" will return false. + * + * @param email The Email address. + * @param emailProvider The Email provider to testify against. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isFromEmailProvider(String email, String emailProvider) { + return extractEmailProvider(email).equalsIgnoreCase(emailProvider); + } + + /** + * Return whether a given Email address is on any of the specified Email providers list (array). E.g. Useful if you pass it a list of real Email provider services and check if the Email is a disposable Email or a real one. + * + * @param email The Email address. + * @param emailProviders The list of Email providers to testify against. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isFromAnyOfEmailProviders(String email, String[] emailProviders) { + return com.blankj.utilcode.util.ArrayUtils.contains(emailProviders, extractEmailProvider(email)); + } + + + + + /** * Return whether input matches regex of exact mobile. * From 402cc73a240a9527cea3180c6cf647223b3e6e91 Mon Sep 17 00:00:00 2001 From: caimengjie Date: Thu, 13 May 2021 01:09:26 +0800 Subject: [PATCH 35/61] add(publish): support publish mavenCentral --- CHANGELOG.md | 1 + build.gradle | 13 +- buildApp.gradle | 44 ++-- buildCommon.gradle | 16 -- buildSrc/src/main/groovy/Config.groovy | 6 +- config/flavor.gradle | 22 ++ config/publish.gradle | 237 ++++++++++++++++++ feature/utilcode/export/build.gradle | 14 +- gradle/publish.gradle | 237 ------------------ gradle/wrapper/gradle-wrapper.properties | 2 +- lib/subutil/build.gradle | 2 +- lib/utilcode/build.gradle | 15 +- lib/utilcode/src/main/AndroidManifest.xml | 2 +- .../com/blankj/utilcode/util/IntentUtils.java | 2 +- .../com/blankj/utilcode/util/ToastUtils.java | 2 +- .../com/blankj/utilcode/util/UriUtils.java | 2 +- lib/utildebug/build.gradle | 4 - plugin/api-gradle-plugin/build.gradle | 6 +- plugin/bus-gradle-plugin/build.gradle | 6 +- plugin/lib/base-transform/build.gradle | 6 +- script/clean.sh | 4 - script/gitHelp.sh | 45 ++++ script/runDevDebug.sh | 9 + script/runProductionRelease.sh | 9 + 24 files changed, 380 insertions(+), 326 deletions(-) create mode 100644 config/flavor.gradle create mode 100644 config/publish.gradle delete mode 100644 gradle/publish.gradle delete mode 100755 script/clean.sh create mode 100755 script/gitHelp.sh create mode 100755 script/runDevDebug.sh create mode 100755 script/runProductionRelease.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index db3e52985a..401a5071f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* `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. diff --git a/build.gradle b/build.gradle index dd27b98617..133f032278 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,9 @@ buildscript { ConfigUtils.init(gradle) repositories { - // use for debug plugin local - if (Config.depConfig.plugin_bus.useLocal || Config.depConfig.plugin_api.useLocal) { - maven() { url uri("${project.rootDir.path}/mavenLocal") } - } + mavenLocal() google() + mavenCentral() jcenter() } @@ -19,9 +17,10 @@ buildscript { allprojects { repositories { - maven() { url uri("${project.rootDir.path}/mavenLocal") } + mavenLocal() maven { url "https://jitpack.io/" } google() + mavenCentral() jcenter() } @@ -29,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 7aa523c466..d7ed2c75a3 100644 --- a/buildApp.gradle +++ b/buildApp.gradle @@ -1,6 +1,7 @@ apply { plugin "com.android.application" - from "${rootDir.path}/buildCommon.gradle" + from "${rootDir.path}/buildCommon.gradle" + from "${rootDir.path}/config/flavor.gradle" if (Config.depConfig.plugin_api.isApply) { plugin Config.depConfig.plugin_api.pluginId } @@ -32,19 +33,11 @@ android { } buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - applicationIdSuffix ".debug" - resValue "string", "app_name", Config.appName + suffix + ".debug" - } + debug {} release { - aaptOptions.cruncherEnabled = false - aaptOptions.useNewCruncher = false minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - resValue "string", "app_name", Config.appName + suffix } } @@ -58,8 +51,19 @@ 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 @@ -80,7 +84,9 @@ dependencies { 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() { @@ -110,12 +116,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 index f83f74f52d..8cbcc26255 100644 --- a/buildCommon.gradle +++ b/buildCommon.gradle @@ -22,20 +22,4 @@ android { lintOptions { abortOnError false } - -// viewBinding { -// enabled = true -// } - -// flavorDimensions "region" -// -// productFlavors { -// china { -// dimension "region" -// } -// -// oversea { -// dimension "region" -// } -// } } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index 9b6e55d3bb..4fb2b7ef2f 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -15,10 +15,10 @@ class Config { static minSdkVersion = 14 static targetSdkVersion = 29 static versionCode = 1_030_006 - static versionName = '1.30.6'// E.g. 1.9.72 => 1,009,072 + static versionName = '1.30.7-alpha1'// E.g. 1.9.72 => 1,009,072 // lib version - static gradlePluginVersion = '3.5.2' + static gradlePluginVersion = '4.1.0' static kotlinVersion = '1.3.72' static androidxVersion = '1.0.0' @@ -47,8 +47,6 @@ class Config { /*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"),// 注解转非空判断 // 上传新版本插件更新 pluginPath 中的版本号,并设置 isApply = false diff --git a/config/flavor.gradle b/config/flavor.gradle new file mode 100644 index 0000000000..25c1801983 --- /dev/null +++ b/config/flavor.gradle @@ -0,0 +1,22 @@ +android { + flavorDimensions "env" + productFlavors { + dev { + dimension "env" + } + + production { + dimension "env" + } + } + + variantFilter { variant -> + def flavorNames = variant.flavors*.name + def buildTypeName = variant.buildType.name + + // production 包不允许 debug 构建 + if (flavorNames.contains("production") && buildTypeName.contains("debug")) { + variant.setIgnore(true) + } + } +} \ No newline at end of file diff --git a/config/publish.gradle b/config/publish.gradle new file mode 100644 index 0000000000..af97da785b --- /dev/null +++ b/config/publish.gradle @@ -0,0 +1,237 @@ +/* + 1. add + signing.keyId=xx + signing.password=xx + signing.secretKeyRingFile=/Users/xx/secring.gpg + ossrhUsername=xx + ossrhPassword=xx + in root local.properties + + 2. copy the file to the directory of gradle, and apply the file in the module + ext { + groupId = Config.depConfig.lib_utilcode.groupId + artifactId = Config.depConfig.lib_utilcode.artifactId + version = Config.depConfig.lib_utilcode.version + website = "https://github.com/Blankj/AndroidUtilCode" +} + apply from: "${rootDir.path}/config/publish.gradle" + + 3. execute following command to publish + ./gradlew :xxmodule:publish2Local -> upload to mavenCentral + ./gradlew :xxmodule:publish2Remote -> upload to mavenLocal +*/ + +apply plugin: 'maven-publish' +apply plugin: 'signing' + +ext.multiPublishMode = true + +File localPropertiesFile = project.rootProject.file("local.properties"); +if (localPropertiesFile.exists()) { + Properties properties = new Properties() + properties.load(new FileInputStream(localPropertiesFile)) + properties.each { name, value -> ext[name] = value } +} else { + if (!ext["signing.keyId"] && !ext["signing.password"] && + !ext["signing.secretKeyRingFile"] && + !ext["ossrhUsername"] && + !ext["ossrhPassword"]) { + throw new NullPointerException("U should set MavenCentral params in local.properties") + } +} + +afterEvaluate { + def ext = project.ext + publishing { + publications { + release(MavenPublication) { + groupId ext.groupId + artifactId ext.artifactId + version ext.version + + if (isAndroidEnv(project)) { + if (project.ext.multiPublishMode) { + artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") + artifact sourcesJar + } else { + from project.components.release + } + } else { + from project.components.java + } + + pom { + name = ext.artifactId + description = ext.artifactId + url = ext.website + + licenses { + license { + name = 'The Apache Software License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + developers { + developer { + id = ext.ossrhUsername + name = ext.ossrhUsername + } + } + scm { + url = ext.website + connection = ext.website + developerConnection = ext.website + ".git" + } + + if (project.ext.multiPublishMode) { + withXml { + def dependenciesNode = asNode().getAt('dependencies')[0] ?: + asNode().appendNode('dependencies') + + configurations. + api. + getDependencies(). + each { dep -> addDependency(project, dependenciesNode, dep, "compile") } + configurations. + implementation. + getDependencies(). + each { dep -> addDependency(project, dependenciesNode, dep, "runtime") } + } + } + } + } + } + + repositories { + maven { + // s01 is newest + def releasesUrl = "https://s01.oss.sonatype.org/content/repositories/releases/" + def snapshotUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" + url = version.toUpperCase().endsWith('SNAPSHOT') ? snapshotUrl : releasesUrl + + credentials { + username ossrhUsername + password ossrhPassword + } + } + } + } + + signing { + sign publishing.publications + } +} + +private void addDependency(Project project, def dependenciesNode, Dependency dep, String scope) { + if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") { + return + } + + final dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('scope', scope) + + if (dep.version == 'unspecified') { + // 检测 module 中的 dependencies 是否有源码依赖 + // 如果是源码依赖,而且没有在 config 中配置 remotePath, + // 那么发布到仓库,其他地方依赖该库时会找不到源码的那个库 + println "publish -> module(unspecified) <${dep.group}:${dep.name}:${dep.version}>" + if (project.ext.groupId || project.ext.version) { + throw new GradleException( + "The module of <" + dep.name + "> should set groupId & version.") + } + // 源码依赖,但配置了 remotePath,让 pom 中写入 remotePath + println( + "publish -> module(wrapped) <${project.ext.groupId}:${name}:${project.ext.version}>") + + dependencyNode.appendNode('groupId', project.ext.pomGroupID) + dependencyNode.appendNode('artifactId', dep.name) + dependencyNode.appendNode('version', project.ext.pomVersion) + } else { + dependencyNode.appendNode('groupId', dep.group) + dependencyNode.appendNode('artifactId', dep.name) + dependencyNode.appendNode('version', dep.version) + println("publish -> library <${dep.group}:${dep.name}:${dep.version}>") + } + + if (!dep.transitive) { + // In case of non transitive dependency, + // all its dependencies should be force excluded from them POM file + final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion') + exclusionNode.appendNode('groupId', '*') + exclusionNode.appendNode('artifactId', '*') + } else if (!dep.properties.excludeRules.empty) { + // For transitive with exclusions, all exclude rules should be added to the POM file + final exclusions = dependencyNode.appendNode('exclusions') + dep.properties.excludeRules.each { ExcludeRule rule -> + final exclusionNode = exclusions.appendNode('exclusion') + exclusionNode.appendNode('groupId', rule.group ?: '*') + exclusionNode.appendNode('artifactId', rule.module ?: '*') + } + } +} + +if (isAndroidEnv(project)) { + // 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 project.ext.version + links "http://docs.oracle.com/javase/7/docs/api" + title "${project.ext.artifactId} ${project.ext.version}" + } +} + +artifacts { + archives javadocJar + archives sourcesJar +} + +static def isAndroidEnv(Project project) { + return project.getPlugins().hasPlugin('com.android.application') || project. + getPlugins(). + hasPlugin('com.android.library') +} + +task publish2Local(type: GradleBuild) { + tasks = ['clean', 'assemble', 'publishReleasePublicationToMavenLocal'] +} + +task publish2Remote(type: GradleBuild) { + tasks = ['clean', 'assemble', 'publishReleasePublicationToMavenRepository'] +} \ No newline at end of file diff --git a/feature/utilcode/export/build.gradle b/feature/utilcode/export/build.gradle index cecc254461..815f9babe6 100644 --- a/feature/utilcode/export/build.gradle +++ b/feature/utilcode/export/build.gradle @@ -1,10 +1,8 @@ -apply from: "${rootDir.path}/gradle/publish.gradle" -publish { - def depConfig = Config.depConfig.feature_utilcode_export - name = "UtilCodeExport" - groupId = depConfig.groupId - artifactId = depConfig.artifactId - version = depConfig.version - website = "https://github.com/Blankj/UtilCodeExport" +ext { + groupId = Config.depConfig.feature_utilcode_export.groupId + artifactId = Config.depConfig.feature_utilcode_export.artifactId + version = Config.depConfig.feature_utilcode_export.version + website = "https://github.com/Blankj/AndroidUtilCode" } +apply from: "${rootDir.path}/config/publish.gradle" //./gradlew :feature_utilcode_export:mavenLocal // 上传到本地 mavenLocal \ No newline at end of file diff --git a/gradle/publish.gradle b/gradle/publish.gradle deleted file mode 100644 index 76bb5fea66..0000000000 --- a/gradle/publish.gradle +++ /dev/null @@ -1,237 +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) { - group("publishing") - configuration = project.configurations.archives - - repositories.mavenDeployer { - repository(url: uri("${project.rootDir.path}/mavenLocal")) - configPom(pom, ext) - } - - doFirst { - ext.check(false) - } - } - - project.tasks.findByName("bintrayUpload").doFirst { - ext.check(true) - } -} - -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 - } - } - } - - pom.whenConfigured { - // 检测 module 中的 dependencies 是否有源码依赖 - // 如果是源码依赖,而且没有在 config 中配置 remotePath,那么发布到仓库,其他地方依赖该库时会找不到源码的那个库 - it.dependencies.findAll { dep -> dep.version == "unspecified" }.collect { dep -> - DepConfig config = Config.depConfig.get(dep.artifactId) - if (config == null || config.version == null) { - // 源码依赖而且没有在 config 中配置 remotePath,直接报错 - System.err.println("The module of <" + dep.artifactId + "> should publish to maven first.") - throw new RuntimeException() - } - dep.groupId = config.groupId - dep.version = config.version - // 源码依赖,但配置了 remotePath,让 pom 中写入 remotePath - GLog.l("Please check <${dep.groupId}:${dep.artifactId}:${dep.version}> is published.") - } - } -} - -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(boolean isBintray) { - checkField(name, "name") - checkField(groupId, "groupId") - checkField(artifactId, "artifactId") - checkField(version, "version") - checkField(website, "website") - - if (isBintray) { - if (isBintrayEmpty()) { - throw new NullPointerException("U should set bintrayUser and bintrayKey in local.properties") - } - } - } - - 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.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/lib/subutil/build.gradle b/lib/subutil/build.gradle index a561916f3e..1d2b458537 100644 --- a/lib/subutil/build.gradle +++ b/lib/subutil/build.gradle @@ -1,5 +1,5 @@ apply { - plugin Config.depConfig.plugin_traute.pluginId +// plugin Config.depConfig.plugin_traute.pluginId plugin "readme-sub" } diff --git a/lib/utilcode/build.gradle b/lib/utilcode/build.gradle index 891f7dbf40..612969a45c 100644 --- a/lib/utilcode/build.gradle +++ b/lib/utilcode/build.gradle @@ -1,5 +1,5 @@ apply { - plugin Config.depConfig.plugin_traute.pluginId + // plugin Config.depConfig.plugin_traute.pluginId plugin "readme-core" } @@ -29,7 +29,7 @@ android { dependencies { implementation Config.depConfig.gson.dep - compileOnly Config.depConfig.androidx_appcompat.dep + implementation Config.depConfig.androidx_appcompat.dep compileOnly Config.depConfig.androidx_material.dep testImplementation Config.depConfig.test_junit.dep @@ -39,15 +39,10 @@ dependencies { testImplementation Config.depConfig.eventbus_lib.dep } -afterEvaluate { - verifyReleaseResources.enabled(false) -} - -apply from: "${rootDir.path}/gradle/publish.gradle" -publish { - name = "UtilCodeX" +ext { groupId = Config.depConfig.lib_utilcode.groupId artifactId = Config.depConfig.lib_utilcode.artifactId version = Config.depConfig.lib_utilcode.version website = "https://github.com/Blankj/AndroidUtilCode" -} \ No newline at end of file +} +apply from: "${rootDir.path}/config/publish.gradle" \ No newline at end of file diff --git a/lib/utilcode/src/main/AndroidManifest.xml b/lib/utilcode/src/main/AndroidManifest.xml index 4cf4fe1090..fc5b75e0e3 100644 --- a/lib/utilcode/src/main/AndroidManifest.xml +++ b/lib/utilcode/src/main/AndroidManifest.xml @@ -18,7 +18,7 @@ = Build.VERSION_CODES.N) { - String authority = Utils.getApp().getPackageName() + ".utilcode.provider"; + String authority = Utils.getApp().getPackageName() + ".utilcode.fileprovider"; return FileProvider.getUriForFile(Utils.getApp(), authority, file); } else { return Uri.fromFile(file); diff --git a/lib/utildebug/build.gradle b/lib/utildebug/build.gradle index 4dd4682f3c..22f1f7294b 100644 --- a/lib/utildebug/build.gradle +++ b/lib/utildebug/build.gradle @@ -1,7 +1,3 @@ -afterEvaluate { - verifyReleaseResources.enabled(false) -} - dependencies { compileOnly Config.depConfig.androidx_appcompat.dep compileOnly Config.depConfig.androidx_material.dep diff --git a/plugin/api-gradle-plugin/build.gradle b/plugin/api-gradle-plugin/build.gradle index 8b859f35a6..2f6b956ee0 100755 --- a/plugin/api-gradle-plugin/build.gradle +++ b/plugin/api-gradle-plugin/build.gradle @@ -31,14 +31,12 @@ sourceSets { } } -apply from: "${rootDir.path}/gradle/publish.gradle" -publish { - name = "ApiPlugin" +ext { groupId = Config.depConfig.plugin_api.groupId artifactId = Config.depConfig.plugin_api.artifactId version = Config.depConfig.plugin_api.version website = "https://github.com/Blankj/AndroidUtilCode" } - +apply from: "${rootDir.path}/config/publish.gradle" //./gradlew clean :plugin_api-gradle-plugin:mavenLocal // 上传到本地 mavenLocal //./gradlew clean :plugin_api-gradle-plugin:bintrayUpload // 上传到 jcenter diff --git a/plugin/bus-gradle-plugin/build.gradle b/plugin/bus-gradle-plugin/build.gradle index ec264eaf4e..7cd24042a7 100755 --- a/plugin/bus-gradle-plugin/build.gradle +++ b/plugin/bus-gradle-plugin/build.gradle @@ -31,14 +31,12 @@ sourceSets { } } -apply from: "${rootDir.path}/gradle/publish.gradle" -publish { - name = "BusPlugin" +ext { groupId = Config.depConfig.plugin_bus.groupId artifactId = Config.depConfig.plugin_bus.artifactId version = Config.depConfig.plugin_bus.version website = "https://github.com/Blankj/AndroidUtilCode" } - +apply from: "${rootDir.path}/config/publish.gradle" //./gradlew clean :plugin_bus-gradle-plugin:mavenLocal // 上传到本地 mavenLocal //./gradlew clean :plugin_bus-gradle-plugin:bintrayUpload // 上传到 jcenter \ No newline at end of file diff --git a/plugin/lib/base-transform/build.gradle b/plugin/lib/base-transform/build.gradle index 72d0abe453..3518481ebd 100755 --- a/plugin/lib/base-transform/build.gradle +++ b/plugin/lib/base-transform/build.gradle @@ -18,14 +18,12 @@ sourceSets { } } -apply from: "${rootDir.path}/gradle/publish.gradle" -publish { - name = "BaseTransform" +ext { groupId = Config.depConfig.plugin_lib_base_transform.groupId artifactId = Config.depConfig.plugin_lib_base_transform.artifactId version = Config.depConfig.plugin_lib_base_transform.version website = "https://github.com/Blankj/AndroidUtilCode" } - +apply from: "${rootDir.path}/config/publish.gradle" //./gradlew clean plugin:lib:plugin_lib_base-transform:mavenLocal // 上传到本地 mavenLocal //./gradlew clean plugin:lib:plugin_lib_base-transform:bintrayUpload // 上传到 gradle 插件库中 diff --git a/script/clean.sh b/script/clean.sh deleted file mode 100755 index 2ff72056bb..0000000000 --- a/script/clean.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -rm -rf .idea -find . -name "*.iml" -type f -exec rm -rf {} \; -find . -name "build" -type d -exec rm -rf {} \; \ No newline at end of file diff --git a/script/gitHelp.sh b/script/gitHelp.sh new file mode 100755 index 0000000000..af98ce2ac6 --- /dev/null +++ b/script/gitHelp.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +while true; do + echo " ############## input command code #################" + echo " # [1] Git Push #" + echo " # [2] Git Push And Merge to Master #" + echo " # [other] exit #" + echo " ###################################################" + + read which + + case $which in + 1) + curBranch=$(git symbolic-ref --short -q HEAD) + gitPush $curBranch + ;; + 2) + curBranch=$(git symbolic-ref --short -q HEAD) + gitPush $curBranch + echo "git checkout master" + echo $(git checkout master) + echo "git merge $branchName" + echo $(git merge $branchName) + echo "git push origin master" + echo $(git push origin master) + echo "git checkout $branchName" + echo $(git checkout $branchName) + ;; + *) + echo "88" + break + ;; + esac +done + +function gitPush() { + curBranch=$1 + echo "curBranch = $curBranch" + echo "git add -A" + echo $(git add -A) + date=$(date "+%m/%d") + echo "git commit -m \"see $date log\"" + echo $(git commit -m "see $date log") + echo "git push origin $curBranch" + echo $(git push origin $curBranch) +} diff --git a/script/runDevDebug.sh b/script/runDevDebug.sh new file mode 100755 index 0000000000..e42394e0c8 --- /dev/null +++ b/script/runDevDebug.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +# build dev debug apk +./gradlew --daemon installDevDebug + +# start main activity +adb shell am start -n "com.blankj.androidutilcode.dev/com.blankj.main.pkg.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER \ No newline at end of file diff --git a/script/runProductionRelease.sh b/script/runProductionRelease.sh new file mode 100755 index 0000000000..a3d44d5ede --- /dev/null +++ b/script/runProductionRelease.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +# build dev debug apk +./gradlew --daemon installProductionRelease + +# start main activity +adb shell am start -n "com.blankj.androidutilcode/com.blankj.main.pkg.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER \ No newline at end of file From 8faee0b382724d3579921672f8a5dbb9c9360f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=AD=87=E5=B0=94?= Date: Wed, 22 Sep 2021 13:39:01 -0600 Subject: [PATCH 36/61] isUsingNetworkProvidedTime() Useful in situations where you want to verify that the device has a correct time set, to avoid fraud, or if you want to prevent the user from messing with the time and abusing your "one-time" and "expiring" features. --- .../java/com/blankj/utilcode/util/TimeUtils.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java index 2ab5370c82..88887b621f 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java @@ -36,6 +36,19 @@ protected Map initialValue() { private static SimpleDateFormat getDefaultFormat() { return getSafeDateFormat("yyyy-MM-dd HH:mm:ss"); } + /** + * Checks whether the device is using Network Provided Time or not. + * Useful in situations where you want to verify that the device has a correct time set, to avoid fraud, or if you want to prevent the user from messing with the time and abusing your "one-time" and "expiring" features. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isUsingNetworkProvidedTime() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return Settings.Global.getInt(Utils.getApp().getContentResolver(), Settings.Global.AUTO_TIME, 0) == 1; + } else { + return android.provider.Settings.System.getInt(Utils.getApp().getContentResolver(), android.provider.Settings.System.AUTO_TIME, 0) == 1; + } + } + @SuppressLint("SimpleDateFormat") public static SimpleDateFormat getSafeDateFormat(String pattern) { From fb1f0d0a616bbbb326e9c7665887365c5dd064f9 Mon Sep 17 00:00:00 2001 From: jikun2008 Date: Wed, 10 Nov 2021 16:52:17 +0800 Subject: [PATCH 37/61] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit //这里会发生内存泄漏 如果不设置为null contentView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, null); --- .../src/main/java/com/blankj/utilcode/util/KeyboardUtils.java | 2 ++ 1 file changed, 2 insertions(+) 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 7f95fdee75..fd70fef220 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 @@ -238,6 +238,8 @@ public static void unregisterSoftInputChangedListener(@NonNull final Window wind 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); } } } From 9df5d7e15b06109153d0499c3f1ed1a3080c94ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=AD=87=E5=B0=94?= Date: Tue, 23 Nov 2021 22:19:24 +0100 Subject: [PATCH 38/61] 2 new methods: isJSONObject() and isJSONArray() Check if a given input is a JSONObject or a JSONArray. --- .../com/blankj/utilcode/util/JsonUtils.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 ea40ac3162..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 @@ -26,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); From e40b6d40b55cfb3608cd954d6bdd1feac67b94ca Mon Sep 17 00:00:00 2001 From: caimengjie Date: Mon, 6 Dec 2021 00:00:20 +0800 Subject: [PATCH 39/61] opt: Config --- build.gradle | 4 +- buildApp.gradle | 43 ++-- buildCommon.gradle | 5 + buildLib.gradle | 2 +- buildSrc/settings.gradle | 8 + buildSrc/src/main/groovy/Config.groovy | 114 ++++----- buildSrc/src/main/groovy/ConfigUtils.groovy | 45 ++-- buildSrc/src/main/groovy/DepConfig.groovy | 93 ------- buildSrc/src/main/groovy/GitUtils.groovy | 111 --------- buildSrc/src/main/groovy/LibConfig.groovy | 29 +++ buildSrc/src/main/groovy/ModuleConfig.groovy | 35 +++ buildSrc/src/main/groovy/PluginConfig.groovy | 35 +++ buildSrc/src/main/groovy/ShellUtils.java | 228 ------------------ .../src/main/groovy/TaskDurationUtils.groovy | 5 + config.json | 28 --- config/publish.gradle | 52 ++-- feature/launcher/app/build.gradle | 2 +- feature/utilcode/export/build.gradle | 8 +- gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 55616 bytes gradlew | 88 ++++--- gradlew.bat | 190 ++++++++------- lib/base/build.gradle | 23 +- .../java/com/blankj/base/rv/BaseItem.java | 6 +- lib/common/build.gradle | 2 +- lib/subutil/build.gradle | 19 +- lib/utilcode/README-CN.md | 1 + lib/utilcode/build.gradle | 23 +- .../blankj/utilcode/util/ActivityUtils.java | 3 +- .../com/blankj/utilcode/util/AppUtils.java | 16 ++ .../com/blankj/utilcode/util/CrashUtils.java | 30 ++- .../blankj/utilcode/util/KeyboardUtils.java | 127 ++++++---- .../blankj/utilcode/util/MetaDataUtils.java | 2 +- .../com/blankj/utilcode/util/SpanUtils.java | 26 +- .../util/UtilsActivityLifecycleImpl.java | 19 +- lib/utildebug/build.gradle | 16 +- .../com/blankj/utildebug/menu/DebugMenu.java | 1 + module_config.gradle | 72 ++++++ module_config.json | 30 +++ module_config.yaml | 91 +++++++ plugin/api-gradle-plugin/build.gradle | 20 +- plugin/buildSrc-plugin/.gitignore | 1 + plugin/buildSrc-plugin/build.gradle | 37 +++ .../com/blankj/buildSrc/BuildSrcPlugin.groovy | 13 + .../java/com/blankj/buildSrc/ModuleCfg.groovy | 80 ++++++ plugin/bus-gradle-plugin/build.gradle | 18 +- plugin/lib/base-transform/build.gradle | 14 +- settings.gradle | 112 +++------ 47 files changed, 968 insertions(+), 959 deletions(-) create mode 100644 buildSrc/settings.gradle delete mode 100644 buildSrc/src/main/groovy/DepConfig.groovy delete mode 100644 buildSrc/src/main/groovy/GitUtils.groovy create mode 100644 buildSrc/src/main/groovy/LibConfig.groovy create mode 100644 buildSrc/src/main/groovy/ModuleConfig.groovy create mode 100644 buildSrc/src/main/groovy/PluginConfig.groovy delete mode 100644 buildSrc/src/main/groovy/ShellUtils.java delete mode 100644 config.json create mode 100644 module_config.gradle create mode 100644 module_config.json create mode 100644 module_config.yaml create mode 100755 plugin/buildSrc-plugin/.gitignore create mode 100755 plugin/buildSrc-plugin/build.gradle create mode 100644 plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/BuildSrcPlugin.groovy create mode 100644 plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/ModuleCfg.groovy diff --git a/build.gradle b/build.gradle index 133f032278..e0f0f36c87 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { dependencies { for (def entrySet : ConfigUtils.getApplyPlugins().entrySet()) { - classpath entrySet.value.dep + classpath entrySet.value.path } } } @@ -29,7 +29,7 @@ allprojects { resolutionStrategy.eachDependency { if (it.requested.group == 'com.android.support' && !it.requested.name.contains( - 'multidex')) { + 'multidex')) { it.useVersion Config.supportVersion } } diff --git a/buildApp.gradle b/buildApp.gradle index d7ed2c75a3..93f0b9b1d4 100644 --- a/buildApp.gradle +++ b/buildApp.gradle @@ -1,29 +1,30 @@ +apply plugin: "com.android.application" + apply { - plugin "com.android.application" from "${rootDir.path}/buildCommon.gradle" from "${rootDir.path}/config/flavor.gradle" - if (Config.depConfig.plugin_api.isApply) { - plugin Config.depConfig.plugin_api.pluginId + 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 { defaultConfig { @@ -67,18 +68,18 @@ android { dependencies { // LeakCanary - debugImplementation Config.depConfig.leakcanary.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 } } diff --git a/buildCommon.gradle b/buildCommon.gradle index 8cbcc26255..2cba3ffea2 100644 --- a/buildCommon.gradle +++ b/buildCommon.gradle @@ -19,6 +19,11 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + lintOptions { abortOnError false } diff --git a/buildLib.gradle b/buildLib.gradle index ac9c42ac1c..aed207cbee 100644 --- a/buildLib.gradle +++ b/buildLib.gradle @@ -8,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 4fb2b7ef2f..4a0b27a980 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,74 +6,84 @@ class Config { static compileSdkVersion = 29 static minSdkVersion = 14 static targetSdkVersion = 29 - static versionCode = 1_030_006 - static versionName = '1.30.7-alpha1'// E.g. 1.9.72 => 1,009,072 + static versionCode = 1_030_007 + static versionName = '1.31.0'// E.g. 1.9.72 => 1,009,072 // lib version 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"), - plugin_lib_base_transform : new DepConfig(true , false, ":plugin:lib:base-transform", "com.blankj:base-transform:1.0"), - 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", "com.blankj:utilcode-export:1.1"), - 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:utilcodex:$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_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: false, localPath: "./lib/utilcode", remotePath: "com.blankj:utilcode:$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.5", pluginId: "com.blankj.api"), + 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 DepConfig(isApply: true, useLocal: false, pluginPath: "com.blankj:bus-gradle-plugin:2.6", pluginId: "com.blankj.bus"), + 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: true, 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 + ] - androidx_appcompat : new DepConfig("androidx.appcompat:appcompat:$androidxVersion"), - androidx_material : new DepConfig("com.google.android.material:material:$androidxVersion"), - androidx_multidex : new DepConfig("androidx.multidex:multidex:2.0.0"), - androidx_constraint : new DepConfig("androidx.constraintlayout:constraintlayout: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 : 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_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 d60518fac5..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 entry : Config.depConfig.entrySet()) { + for (Map.Entry entry : Config.modules.entrySet()) { def (name, config) = [entry.key, entry.value] - if (entry.value.pluginPath) { - config.dep = config.pluginPath + if (config.useLocal) { + config.dep = gradle.rootProject.findProject(name) } else { - if (config.useLocal) { - config.dep = gradle.rootProject.findProject(config.projectPath) - } else { - config.dep = config.remotePath - } + config.dep = config.remotePath } configs.put(name, config) } @@ -46,20 +41,18 @@ class ConfigUtils { @Override void beforeEvaluate(Project project) { // 在 project 的 build.gradle 前 do sth. - if (project.subprojects.isEmpty()) { - if (project.path.startsWith(":plugin")) { - return + if (project.name.contains("plugin")) { + return + } + if (project.name.endsWith("_app")) { + GLog.l(project.toString() + " applies buildApp.gradle") + project.apply { + from "${project.rootDir.path}/buildApp.gradle" } - if (project.name.endsWith("_app")) { - GLog.l(project.toString() + " applies buildApp.gradle") - project.apply { - from "${project.rootDir.path}/buildApp.gradle" - } - } else { - GLog.l(project.toString() + " applies buildLib.gradle") - project.apply { - from "${project.rootDir.path}/buildLib.gradle" - } + } else { + GLog.l(project.toString() + " applies buildLib.gradle") + project.apply { + from "${project.rootDir.path}/buildLib.gradle" } } } @@ -73,8 +66,8 @@ class ConfigUtils { static getApplyPlugins() { def plugins = [:] - for (Map.Entry entry : Config.depConfig.entrySet()) { - if (entry.value.isApply && entry.value.pluginPath) { + for (Map.Entry entry : Config.plugins.entrySet()) { + if (entry.value.isApply) { plugins.put(entry.key, entry.value) } } @@ -84,7 +77,7 @@ class ConfigUtils { static getApplyPkgs() { def pkgs = [:] - for (Map.Entry entry : Config.depConfig.entrySet()) { + for (Map.Entry entry : Config.modules.entrySet()) { if (entry.value.isApply && entry.key.endsWith("_pkg")) { pkgs.put(entry.key, entry.value) } @@ -95,7 +88,7 @@ class ConfigUtils { static getApplyExports() { def exports = [:] - for (Map.Entry entry : Config.depConfig.entrySet()) { + for (Map.Entry entry : Config.modules.entrySet()) { if (entry.value.isApply && entry.key.endsWith("_export")) { exports.put(entry.key, entry.value) } diff --git a/buildSrc/src/main/groovy/DepConfig.groovy b/buildSrc/src/main/groovy/DepConfig.groovy deleted file mode 100644 index 042b67036d..0000000000 --- a/buildSrc/src/main/groovy/DepConfig.groovy +++ /dev/null @@ -1,93 +0,0 @@ -/** - *
- *     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(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 commands) { - return execCmd(commands == null ? null : commands.toArray(new String[]{}), false, true); - } - - /** - * Execute the command. - * - * @param commands The commands. - * @param isRooted True to use root, false otherwise. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final List commands, final boolean isRooted) { - return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true); - } - - /** - * Execute the command. - * - * @param commands The commands. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final String[] commands) { - return execCmd(commands, false, true); - } - - /** - * Execute the command. - * - * @param commands The commands. - * @param isRooted True to use root, false otherwise. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final String[] commands, final boolean isRooted) { - return execCmd(commands, isRooted, true); - } - - /** - * Execute the command. - * - * @param command The command. - * @param isRooted True to use root, false otherwise. - * @param isNeedResultMsg True to return the message of result, false otherwise. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final String command, - final boolean isRooted, - final boolean isNeedResultMsg) { - return execCmd(new String[]{command}, isRooted, isNeedResultMsg); - } - - /** - * Execute the command. - * - * @param commands The commands. - * @param isRooted True to use root, false otherwise. - * @param isNeedResultMsg True to return the message of result, false otherwise. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final List commands, - final boolean isRooted, - final boolean isNeedResultMsg) { - return execCmd(commands == null ? null : commands.toArray(new String[]{}), - isRooted, - isNeedResultMsg); - } - - /** - * Execute the command. - * - * @param commands The commands. - * @param isRooted True to use root, false otherwise. - * @param isNeedResultMsg True to return the message of result, false otherwise. - * @return the single {@link CommandResult} instance - */ - public static CommandResult execCmd(final String[] commands, - final boolean isRooted, - final boolean isNeedResultMsg) { - int result = -1; - if (commands == null || commands.length == 0) { - return new CommandResult(result, "", ""); - } - Process process = null; - BufferedReader successResult = null; - BufferedReader errorResult = null; - StringBuilder successMsg = null; - StringBuilder errorMsg = null; - DataOutputStream os = null; - try { - process = Runtime.getRuntime().exec(isRooted ? "su" : "sh"); - os = new DataOutputStream(process.getOutputStream()); - for (String command : commands) { - if (command == null) continue; - os.write(command.getBytes()); - os.writeBytes(LINE_SEP); - os.flush(); - } - os.writeBytes("exit" + LINE_SEP); - os.flush(); - result = process.waitFor(); - if (isNeedResultMsg) { - successMsg = new StringBuilder(); - errorMsg = new StringBuilder(); - successResult = new BufferedReader( - new InputStreamReader(process.getInputStream(), "UTF-8") - ); - errorResult = new BufferedReader( - new InputStreamReader(process.getErrorStream(), "UTF-8") - ); - String line; - if ((line = successResult.readLine()) != null) { - successMsg.append(line); - while ((line = successResult.readLine()) != null) { - successMsg.append(LINE_SEP).append(line); - } - } - if ((line = errorResult.readLine()) != null) { - errorMsg.append(line); - while ((line = errorResult.readLine()) != null) { - errorMsg.append(LINE_SEP).append(line); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (os != null) { - os.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - try { - if (successResult != null) { - successResult.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - try { - if (errorResult != null) { - errorResult.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - if (process != null) { - process.destroy(); - } - } - return new CommandResult( - result, - successMsg == null ? "" : successMsg.toString(), - errorMsg == null ? "" : errorMsg.toString() - ); - } - - /** - * The result of command. - */ - public static class CommandResult { - public int result; - public String successMsg; - public String errorMsg; - - public CommandResult(final int result, final String successMsg, final String errorMsg) { - this.result = result; - this.successMsg = successMsg; - this.errorMsg = errorMsg; - } - - @Override - public String toString() { - return "result: " + result + "\n" + - "successMsg: " + successMsg + "\n" + - "errorMsg: " + errorMsg; - } - } -} diff --git a/buildSrc/src/main/groovy/TaskDurationUtils.groovy b/buildSrc/src/main/groovy/TaskDurationUtils.groovy index 9ff2722345..6aacfcf30f 100644 --- a/buildSrc/src/main/groovy/TaskDurationUtils.groovy +++ b/buildSrc/src/main/groovy/TaskDurationUtils.groovy @@ -38,6 +38,11 @@ class TaskDurationUtils { } }) grd.addBuildListener(new BuildListener() { + @Override + void beforeSettings(Settings settings) { + super.beforeSettings(settings) + } + @Override void buildStarted(Gradle gradle) {} diff --git a/config.json b/config.json deleted file mode 100644 index c4c025e27b..0000000000 --- a/config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "appConfigDesc": "appConfig 配置的是可以跑 app 的模块,git 提交务必只包含 launcher", - "appConfig": ["launcher"], - "pkgConfigDesc": "pkgConfig 配置的是要依赖的功能包,为空则依赖全部,git 提交务必为空", - "pkgConfig": [], - "proConfigDesc": "proConfig 配置的是使用本地还是仓库,优先级低于 appConfig 和 pkgConfig", - "proConfig": [ - {"isApply": true, "useLocal": true, "localPath": ":plugin:api-gradle-plugin"}, - {"isApply": true, "useLocal": true, "localPath": ":plugin:bus-gradle-plugin"}, - {"isApply": true, "useLocal": false, "localPath": ":plugin:lib:base-transform", "remotePath": "com.blankj:base-transform:1.0"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:mock"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:launcher:app"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:main:app"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:main:pkg"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:subutil:app"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:subutil:pkg"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:subutil:export"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:utilcode:app"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:utilcode:pkg"}, - {"isApply": true, "useLocal": true, "localPath": ":feature:utilcode:export", "remotePath": "com.blankj:utilcode-export:1.1"}, - {"isApply": true, "useLocal": true, "localPath": ":lib:base"}, - {"isApply": true, "useLocal": true, "localPath": ":lib:common"}, - {"isApply": true, "useLocal": true, "localPath": ":lib:subutil"}, - {"isApply": true, "useLocal": true, "localPath": ":lib:utilcode", "remotePath": "com.blankj:utilcodex:$versionName"}, - {"isApply": true, "useLocal": true, "localPath": ":lib:utildebug"}, - {"isApply": true, "useLocal": true, "localPath": ":lib:utildebug-no-op"} - ] -} diff --git a/config/publish.gradle b/config/publish.gradle index af97da785b..fa8a449f3c 100644 --- a/config/publish.gradle +++ b/config/publish.gradle @@ -9,16 +9,16 @@ 2. copy the file to the directory of gradle, and apply the file in the module ext { - groupId = Config.depConfig.lib_utilcode.groupId - artifactId = Config.depConfig.lib_utilcode.artifactId - version = Config.depConfig.lib_utilcode.version + groupId = Config.modules.lib_utilcode.groupId + artifactId = Config.modules.lib_utilcode.artifactId + version = Config.modules.lib_utilcode.version website = "https://github.com/Blankj/AndroidUtilCode" } apply from: "${rootDir.path}/config/publish.gradle" 3. execute following command to publish - ./gradlew :xxmodule:publish2Local -> upload to mavenCentral - ./gradlew :xxmodule:publish2Remote -> upload to mavenLocal + ./gradlew :xxmodule:publish2Local -> upload to mavenLocal + ./gradlew :xxmodule:publish2Remote -> upload to mavenCentral */ apply plugin: 'maven-publish' @@ -32,10 +32,8 @@ if (localPropertiesFile.exists()) { properties.load(new FileInputStream(localPropertiesFile)) properties.each { name, value -> ext[name] = value } } else { - if (!ext["signing.keyId"] && !ext["signing.password"] && - !ext["signing.secretKeyRingFile"] && - !ext["ossrhUsername"] && - !ext["ossrhPassword"]) { + if (!ext["signing.keyId"] && !ext["signing.password"] && !ext["signing.secretKeyRingFile"] + && !ext["ossrhUsername"] && !ext["ossrhPassword"]) { throw new NullPointerException("U should set MavenCentral params in local.properties") } } @@ -86,16 +84,14 @@ afterEvaluate { if (project.ext.multiPublishMode) { withXml { def dependenciesNode = asNode().getAt('dependencies')[0] ?: - asNode().appendNode('dependencies') - - configurations. - api. - getDependencies(). - each { dep -> addDependency(project, dependenciesNode, dep, "compile") } - configurations. - implementation. - getDependencies(). - each { dep -> addDependency(project, dependenciesNode, dep, "runtime") } + asNode().appendNode('dependencies') + + configurations.api.getDependencies().each { + dep -> addDependency(project, dependenciesNode, dep, "compile") + } + configurations.implementation.getDependencies().each { + dep -> addDependency(project, dependenciesNode, dep, "runtime") + } } } } @@ -136,12 +132,10 @@ private void addDependency(Project project, def dependenciesNode, Dependency dep // 那么发布到仓库,其他地方依赖该库时会找不到源码的那个库 println "publish -> module(unspecified) <${dep.group}:${dep.name}:${dep.version}>" if (project.ext.groupId || project.ext.version) { - throw new GradleException( - "The module of <" + dep.name + "> should set groupId & version.") + throw new GradleException("The module of <" + dep.name + "> should set groupId & version.") } // 源码依赖,但配置了 remotePath,让 pom 中写入 remotePath - println( - "publish -> module(wrapped) <${project.ext.groupId}:${name}:${project.ext.version}>") + println("publish -> module(wrapped) <${project.ext.groupId}:${name}:${project.ext.version}>") dependencyNode.appendNode('groupId', project.ext.pomGroupID) dependencyNode.appendNode('artifactId', dep.name) @@ -223,15 +217,9 @@ artifacts { } static def isAndroidEnv(Project project) { - return project.getPlugins().hasPlugin('com.android.application') || project. - getPlugins(). - hasPlugin('com.android.library') + return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library') } -task publish2Local(type: GradleBuild) { - tasks = ['clean', 'assemble', 'publishReleasePublicationToMavenLocal'] -} +task publish2Local(type: GradleBuild, dependsOn: ['clean', 'assemble', 'publishReleasePublicationToMavenLocal']) {} -task publish2Remote(type: GradleBuild) { - tasks = ['clean', 'assemble', 'publishReleasePublicationToMavenRepository'] -} \ No newline at end of file +task publish2Remote(type: GradleBuild, dependsOn: ['clean', 'assemble', 'publishReleasePublicationToMavenRepository']) {} \ No newline at end of file diff --git a/feature/launcher/app/build.gradle b/feature/launcher/app/build.gradle index 408db62a67..8f2b6d205d 100644 --- a/feature/launcher/app/build.gradle +++ b/feature/launcher/app/build.gradle @@ -1,5 +1,5 @@ apply plugin: 'kotlin-kapt' dependencies { - kapt Config.depConfig.eventbus_processor.dep + kapt Config.libs.eventbus_processor.path } \ No newline at end of file diff --git a/feature/utilcode/export/build.gradle b/feature/utilcode/export/build.gradle index 815f9babe6..30e59272ee 100644 --- a/feature/utilcode/export/build.gradle +++ b/feature/utilcode/export/build.gradle @@ -1,8 +1,8 @@ ext { - groupId = Config.depConfig.feature_utilcode_export.groupId - artifactId = Config.depConfig.feature_utilcode_export.artifactId - version = Config.depConfig.feature_utilcode_export.version + groupId = Config.modules.feature_utilcode_export.groupId + artifactId = Config.modules.feature_utilcode_export.artifactId + version = Config.modules.feature_utilcode_export.version website = "https://github.com/Blankj/AndroidUtilCode" } -apply from: "${rootDir.path}/config/publish.gradle" +//apply from: "${rootDir.path}/config/publish.gradle" //./gradlew :feature_utilcode_export:mavenLocal // 上传到本地 mavenLocal \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372aef5e24af05341d49695ee84e5f9b594659..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch literal 55616 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�J+L&6O)2CL%pxI@Gv&XXKx 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 V&}jHG \(.*\)$'` + 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 bb7fa31573..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.androidx_appcompat.dep - api Config.depConfig.androidx_material.dep - api Config.depConfig.androidx_multidex.dep - api Config.depConfig.androidx_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/rv/BaseItem.java b/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java index 885fe1a6a5..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 @@ -24,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); @@ -43,6 +44,7 @@ public void partialUpdate(List payloads) { } void bindViewHolder(@NonNull final ItemViewHolder holder, final int position) { + isBindViewHolder = true; if (mOnItemClickListener != null) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override @@ -73,7 +75,9 @@ public boolean onLongClick(View v) { bind(holder, position); } - public void onViewRecycled(@NonNull final ItemViewHolder holder, final int position) {/**/} + public void onViewRecycled(@NonNull final ItemViewHolder holder, final int position) { + isBindViewHolder = false; + } public long getItemId() { return RecyclerView.NO_ID; diff --git a/lib/common/build.gradle b/lib/common/build.gradle index c4bb45fba5..4993b43792 100644 --- a/lib/common/build.gradle +++ b/lib/common/build.gradle @@ -1,4 +1,4 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - api Config.depConfig.lib_base.dep + api Config.modules.lib_base.dep } \ No newline at end of file diff --git a/lib/subutil/build.gradle b/lib/subutil/build.gradle index 1d2b458537..8a697c5a1e 100644 --- a/lib/subutil/build.gradle +++ b/lib/subutil/build.gradle @@ -1,5 +1,4 @@ apply { -// plugin Config.depConfig.plugin_traute.pluginId plugin "readme-sub" } @@ -9,16 +8,16 @@ readme { } dependencies { - compileOnly Config.depConfig.androidx_appcompat.dep - compileOnly Config.depConfig.androidx_material.dep - compileOnly Config.depConfig.lib_utilcode.dep - api(Config.depConfig.glide.dep) { + compileOnly Config.libs.androidx_appcompat.path + compileOnly Config.libs.androidx_material.path + compileOnly Config.modules.lib_utilcode.dep + api(Config.libs.glide.path) { exclude group: "com.android.support" } - api Config.depConfig.retrofit.dep - api Config.depConfig.gson.dep + api Config.libs.retrofit.path + api Config.libs.gson.path - testImplementation Config.depConfig.lib_utilcode.dep - testImplementation Config.depConfig.test_junit.dep - testImplementation Config.depConfig.test_robolectric.dep + testImplementation Config.modules.lib_utilcode.dep + testImplementation Config.libs.test_junit.path + testImplementation Config.libs.test_robolectric.path } \ No newline at end of file diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md index e8edeb5927..79b18eef15 100644 --- a/lib/utilcode/README-CN.md +++ b/lib/utilcode/README-CN.md @@ -78,6 +78,7 @@ getAppSignaturesMD5 : 获取应用签名的的 MD5 值 getAppInfo : 获取 App 信息 getAppsInfo : 获取所有已安装 App 信息 getApkInfo : 获取 Apk 信息 +isFirstTimeInstalled : 判断应用是否首次安装 ``` * ### 数组相关 -> [ArrayUtils.java][array.java] -> [Test][array.test] diff --git a/lib/utilcode/build.gradle b/lib/utilcode/build.gradle index 612969a45c..37a43b0a66 100644 --- a/lib/utilcode/build.gradle +++ b/lib/utilcode/build.gradle @@ -1,5 +1,4 @@ apply { - // plugin Config.depConfig.plugin_traute.pluginId plugin "readme-core" } @@ -27,22 +26,22 @@ android { } dependencies { - implementation Config.depConfig.gson.dep + implementation Config.libs.gson.path - implementation Config.depConfig.androidx_appcompat.dep - compileOnly Config.depConfig.androidx_material.dep + implementation Config.libs.androidx_appcompat.path + compileOnly Config.libs.androidx_material.path - testImplementation Config.depConfig.test_junit.dep - testImplementation Config.depConfig.test_robolectric.dep - testImplementation Config.depConfig.androidx_appcompat.dep - testImplementation Config.depConfig.androidx_material.dep - testImplementation Config.depConfig.eventbus_lib.dep + testImplementation Config.libs.test_junit.path + testImplementation Config.libs.test_robolectric.path + testImplementation Config.libs.androidx_appcompat.path + testImplementation Config.libs.androidx_material.path + testImplementation Config.libs.eventbus_lib.path } ext { - groupId = Config.depConfig.lib_utilcode.groupId - artifactId = Config.depConfig.lib_utilcode.artifactId - version = Config.depConfig.lib_utilcode.version + groupId = Config.modules.lib_utilcode.groupId + artifactId = Config.modules.lib_utilcode.artifactId + version = Config.modules.lib_utilcode.version website = "https://github.com/Blankj/AndroidUtilCode" } apply from: "${rootDir.path}/config/publish.gradle" \ No newline at end of file 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 8191618118..10858f75f4 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 @@ -96,7 +96,8 @@ public static void removeActivityLifecycleCallbacks(@Nullable final Activity act * @return the activity by context. */ @Nullable - public static Activity getActivityByContext(@NonNull Context context) { + public static Activity getActivityByContext(@Nullable Context context) { + if (context == null) return null; Activity activity = getActivityByContextInner(context); if (!isActivityAlive(activity)) return null; return activity; 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 2a5b2ed4ef..8848cbd193 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 @@ -774,6 +774,22 @@ 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; String versionName = pi.versionName; 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 69ae961662..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,15 +1,12 @@ package com.blankj.utilcode.util; -import android.annotation.SuppressLint; - +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; -import androidx.annotation.NonNull; - /** *
  *     author: Blankj
@@ -22,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...");
@@ -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,
@@ -100,15 +99,15 @@ private static UncaughtExceptionHandler getUncaughtExceptionHandler(final String
             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());
                 CrashInfo info = new CrashInfo(time, e);
-                if (onCrashListener != null) {
-                    onCrashListener.onCrash(info);
-                }
                 final String crashFile = dirPath + time + ".txt";
                 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);
+                }
             }
         };
     }
@@ -123,7 +122,7 @@ public interface OnCrashListener {
 
     public static final class CrashInfo {
         private UtilsBridge.FileHead mFileHeadProvider;
-        private Throwable            mThrowable;
+        private Throwable mThrowable;
 
         private CrashInfo(String time, Throwable throwable) {
             mThrowable = throwable;
@@ -145,8 +144,7 @@ public final Throwable getThrowable() {
 
         @Override
         public String toString() {
-            return mFileHeadProvider.toString() +
-                    UtilsBridge.getFullStackTrace(mThrowable);
+            return mFileHeadProvider.toString() + UtilsBridge.getFullStackTrace(mThrowable);
         }
     }
 }
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 f2511e831f..c87687f8a1 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
@@ -17,10 +17,9 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.FrameLayout;
-
-import java.lang.reflect.Field;
-
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import java.lang.reflect.Field;
 
 /**
  * 
@@ -42,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;
         }
@@ -52,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();
         }
@@ -70,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();
@@ -85,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();
                 }
             }
@@ -98,7 +103,10 @@ protected void onReceiveResult(int resultCode, Bundle resultData) {
      *
      * @param activity The activity.
      */
-    public static void hideSoftInput(@NonNull final Activity activity) {
+    public static void hideSoftInput(@Nullable final Activity activity) {
+        if (activity == null) {
+            return;
+        }
         hideSoftInput(activity.getWindow());
     }
 
@@ -107,7 +115,10 @@ public static void hideSoftInput(@NonNull final Activity activity) {
      *
      * @param window The window.
      */
-    public static void hideSoftInput(@NonNull final Window window) {
+    public static void hideSoftInput(@Nullable final Window window) {
+        if (window == null) {
+            return;
+        }
         View view = window.getCurrentFocus();
         if (view == null) {
             View decorView = window.getDecorView();
@@ -131,8 +142,10 @@ public static void hideSoftInput(@NonNull final Window window) {
      */
     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);
     }
 
@@ -143,7 +156,10 @@ public static void hideSoftInput(@NonNull final View view) {
      *
      * @param activity The activity.
      */
-    public static void hideSoftInputByToggle(final Activity activity) {
+    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)) {
@@ -157,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);
     }
 
@@ -178,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;
@@ -195,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() {
@@ -234,11 +254,14 @@ public void onGlobalLayout() {
      */
     public static void unregisterSoftInputChangedListener(@NonNull final Window window) {
         final View contentView = window.findViewById(android.R.id.content);
-        if (contentView == null) return;
+        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);
+                contentView.getViewTreeObserver()
+                    .removeOnGlobalLayoutListener((OnGlobalLayoutListener) tag);
             }
         }
     }
@@ -261,36 +284,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;
@@ -314,9 +336,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);
@@ -324,7 +349,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/MetaDataUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/MetaDataUtils.java
index bd4b8da935..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
@@ -118,7 +118,7 @@ public static String getMetaDataInService(@NonNull final Class getActivitiesByReflect() {
         Activity topActivity = null;
         try {
             Object activityThread = getActivityThread();
+            if (activityThread == null) return list;
             Field mActivitiesField = activityThread.getClass().getDeclaredField("mActivities");
             mActivitiesField.setAccessible(true);
             Object mActivities = mActivitiesField.get(activityThread);
@@ -388,10 +381,10 @@ private List getActivitiesByReflect() {
                     if (!pausedField.getBoolean(activityRecord)) {
                         topActivity = activity;
                     } else {
-                        list.add(activity);
+                        list.addFirst(activity);
                     }
                 } else {
-                    list.add(activity);
+                    list.addFirst(activity);
                 }
             }
         } catch (Exception e) {
diff --git a/lib/utildebug/build.gradle b/lib/utildebug/build.gradle
index 22f1f7294b..d1c5a67273 100644
--- a/lib/utildebug/build.gradle
+++ b/lib/utildebug/build.gradle
@@ -1,12 +1,12 @@
 dependencies {
-    compileOnly Config.depConfig.androidx_appcompat.dep
-    compileOnly Config.depConfig.androidx_material.dep
+    compileOnly Config.libs.androidx_appcompat.path
+    compileOnly Config.libs.androidx_material.path
 
-    implementation Config.depConfig.lib_utilcode.dep
-    implementation Config.depConfig.swipe_panel.dep
-    implementation Config.depConfig.photo_view.dep
+    implementation Config.modules.lib_utilcode.dep
+    implementation Config.libs.swipe_panel.path
+    implementation Config.libs.photo_view.path
 
-    testImplementation Config.depConfig.test_junit.dep
-    testImplementation Config.depConfig.test_robolectric.dep
-    testImplementation Config.depConfig.androidx_appcompat.dep
+    testImplementation Config.libs.test_junit.path
+    testImplementation Config.libs.test_robolectric.path
+    testImplementation Config.libs.androidx_appcompat.path
 }
\ No newline at end of file
diff --git a/lib/utildebug/src/main/java/com/blankj/utildebug/menu/DebugMenu.java b/lib/utildebug/src/main/java/com/blankj/utildebug/menu/DebugMenu.java
index 37c53b89cb..8a0ac4f0f0 100644
--- a/lib/utildebug/src/main/java/com/blankj/utildebug/menu/DebugMenu.java
+++ b/lib/utildebug/src/main/java/com/blankj/utildebug/menu/DebugMenu.java
@@ -56,6 +56,7 @@ protected void onAttachedToWindow() {
 
     @Override
     protected void onDetachedFromWindow() {
+        int a = 0xe1;
         DebugIcon.setVisibility(true);
         super.onDetachedFromWindow();
     }
diff --git a/module_config.gradle b/module_config.gradle
new file mode 100644
index 0000000000..6be8429bd7
--- /dev/null
+++ b/module_config.gradle
@@ -0,0 +1,72 @@
+import groovy.json.JsonSlurper
+
+/**
+ * 在 module_config.json 中 根据 appConfig 和 pkgConfig 来 include 本地模块
+ * 可以考虑写成插件来更方便 apply
+ */
+
+def json = new JsonSlurper().parse(file("./module_config.json"))
+
+for (def module in json.moduleConfig) {
+    String moduleName = module.name
+
+    if (moduleName == "feature_mock") {
+        if (json.pkgConfig.isEmpty()) {
+            module.isApply = false
+        }
+    } else if (moduleName.endsWith("_app")) {
+        if (!json.appConfig.contains(moduleName)) {
+            module.isApply = false
+        }
+    } else if (moduleName.endsWith("_pkg")) {
+        if (!json.pkgConfig.isEmpty()) {
+            if (!json.pkgConfig.contains(moduleName)) {
+                module.isApply = false
+            }
+        }
+    }
+
+    if (module.useLocal && module.isApply) {
+        include moduleName
+        project(":$moduleName").projectDir = file(module.localPath)
+    }
+}
+
+def ls = System.getProperty("line.separator")
+
+List modules = []
+for (def module in json.moduleConfig) {
+    String name = module.name
+    boolean isApply = module.isApply
+    boolean useLocal = module.useLocal
+    String localPath = module.localPath
+    String remotePath = module.remotePath
+    if (localPath != null) localPath = "\"$localPath\""
+    if (remotePath != null) remotePath = "\"$remotePath\""
+    modules.add(String.format("%-12s%-27s: new ModuleConfig(isApply: %-5s, useLocal: %-5s, localPath: $localPath%s),",
+            "", name, isApply, useLocal, remotePath == null ? "" : ", remotePath: $remotePath"))
+}
+
+def configFile = file('./buildSrc/src/main/groovy/Config.groovy')
+def lines = configFile.readLines("utf8")
+def configContent = new StringBuilder()
+
+boolean enterNeverFlag = false
+for (def line : lines) {
+    if (enterNeverFlag) {
+        if (line.contains("/*Don't delete this line*/")) {
+            configContent.append(ls).append(line)
+            enterNeverFlag = false
+        }
+        continue
+    }
+    configContent.append(ls).append(line)
+    if (line.contains("/*Don't delete this line*/")) {
+        configContent.append(ls).append(String.format("%-12s/*Generated by \"module_config.json\"*/", ""))
+        enterNeverFlag = true
+        for (String m : modules) {
+            configContent.append(ls).append(m)
+        }
+    }
+}
+configFile.write(configContent.substring(ls.length()).toString())
\ No newline at end of file
diff --git a/module_config.json b/module_config.json
new file mode 100644
index 0000000000..18f416382a
--- /dev/null
+++ b/module_config.json
@@ -0,0 +1,30 @@
+{
+  "desc": "提交 git 时需要检查下配置是否正确!!!",
+  "appConfigDesc": "appConfig 配置的是可以跑 app 的模块",
+  "appConfig": ["feature_launcher_app"],
+  "pkgConfigDesc": "pkgConfig 配置的是要依赖的功能包,为空则依赖全部",
+  "pkgConfig": [],
+  "moduleConfigDesc": "moduleConfig 配置的是使用本地还是仓库,优先级低于 appConfig 和 pkgConfig",
+  "moduleConfig": [
+    {"name": "plugin_api_gradle_plugin",  "isApply": true, "useLocal": true, "localPath": "./plugin/api-gradle-plugin"},
+    {"name": "plugin_bus_gradle_plugin",  "isApply": true, "useLocal": true, "localPath": "./plugin/bus-gradle-plugin"},
+    {"name": "plugin_lib_base_transform", "isApply": true, "useLocal": true, "localPath": "./plugin/lib/base-transform", "remotePath": "com.blankj:base-transform:1.0"},
+    {"name": "plugin_buildSrc_plugin",    "isApply": true, "useLocal": true, "localPath": "./plugin/buildSrc-plugin"},
+    {"name": "feature_mock",              "isApply": true, "useLocal": true, "localPath": "./feature/mock"},
+    {"name": "feature_launcher_app",      "isApply": true, "useLocal": true, "localPath": "./feature/launcher/app"},
+    {"name": "feature_main_app",          "isApply": true, "useLocal": true, "localPath": "./feature/main/app"},
+    {"name": "feature_main_pkg",          "isApply": true, "useLocal": true, "localPath": "./feature/main/pkg"},
+    {"name": "feature_subutil_app",       "isApply": true, "useLocal": true, "localPath": "./feature/subutil/app"},
+    {"name": "feature_subutil_pkg",       "isApply": true, "useLocal": true, "localPath": "./feature/subutil/pkg"},
+    {"name": "feature_subutil_export",    "isApply": true, "useLocal": true, "localPath": "./feature/subutil/export"},
+    {"name": "feature_utilcode_app",      "isApply": true, "useLocal": true, "localPath": "./feature/utilcode/app"},
+    {"name": "feature_utilcode_pkg",      "isApply": true, "useLocal": true, "localPath": "./feature/utilcode/pkg"},
+    {"name": "feature_utilcode_export",   "isApply": true, "useLocal": true, "localPath": "./feature/utilcode/export", "remotePath": "com.blankj:utilcode-export:1.1"},
+    {"name": "lib_base",                  "isApply": true, "useLocal": true, "localPath": "./lib/base"},
+    {"name": "lib_common",                "isApply": true, "useLocal": true, "localPath": "./lib/common"},
+    {"name": "lib_subutil",               "isApply": true, "useLocal": true, "localPath": "./lib/subutil"},
+    {"name": "lib_utilcode",              "isApply": true, "useLocal": false, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"},
+    {"name": "lib_utildebug",             "isApply": true, "useLocal": true, "localPath": "./lib/utildebug"},
+    {"name": "lib_utildebug_no_op",       "isApply": true, "useLocal": true, "localPath": "./lib/utildebug-no-op"}
+  ]
+}
diff --git a/module_config.yaml b/module_config.yaml
new file mode 100644
index 0000000000..b10ce808e6
--- /dev/null
+++ b/module_config.yaml
@@ -0,0 +1,91 @@
+desc: 提交 git 时需要检查下配置是否正确!!!
+appConfigDesc: appConfig 配置的是可以跑 app 的模块
+appConfig:
+  - feature_launcher_app
+pkgConfigDesc: pkgConfig 配置的是要依赖的功能包,为空则依赖全部
+pkgConfig: [ ]
+moduleConfigDesc: moduleConfig 配置的是使用本地还是仓库,优先级低于 appConfig 和 pkgConfig
+moduleConfig:
+  - name: plugin_api_gradle_plugin
+      isApply: true
+      useLocal: true
+      localPath: ./plugin/api-gradle-plugin
+  - name: plugin_bus_gradle_plugin
+    isApply: true
+    useLocal: true
+    localPath: ./plugin/bus-gradle-plugin
+  - name: plugin_lib_base_transform
+    isApply: true
+    useLocal: true
+    localPath: ./plugin/lib/base-transform
+    remotePath: 'com.blankj:base-transform:1.0'
+  - name: plugin_buildSrc_plugin
+    isApply: true
+    useLocal: true
+    localPath: ./plugin/buildSrc-plugin
+  - name: feature_mock
+    isApply: true
+    useLocal: true
+    localPath: ./feature/mock
+  - name: feature_launcher_app
+    isApply: true
+    useLocal: true
+    localPath: ./feature/launcher/app
+  - name: feature_main_app
+    isApply: true
+    useLocal: true
+    localPath: ./feature/main/app
+  - name: feature_main_pkg
+    isApply: true
+    useLocal: true
+    localPath: ./feature/main/pkg
+  - name: feature_subutil_app
+    isApply: true
+    useLocal: true
+    localPath: ./feature/subutil/app
+  - name: feature_subutil_pkg
+    isApply: true
+    useLocal: true
+    localPath: ./feature/subutil/pkg
+  - name: feature_subutil_export
+    isApply: true
+    useLocal: true
+    localPath: ./feature/subutil/export
+  - name: feature_utilcode_app
+    isApply: true
+    useLocal: true
+    localPath: ./feature/utilcode/app
+  - name: feature_utilcode_pkg
+    isApply: true
+    useLocal: true
+    localPath: ./feature/utilcode/pkg
+  - name: feature_utilcode_export
+    isApply: true
+    useLocal: true
+    localPath: ./feature/utilcode/export
+    remotePath: 'com.blankj:utilcode-export:1.1'
+  - name: lib_base
+    isApply: true
+    useLocal: true
+    localPath: ./lib/base
+  - name: lib_common
+    isApply: true
+    useLocal: true
+    localPath: ./lib/common
+  - name: lib_subutil
+    isApply: true
+    useLocal: true
+    localPath: ./lib/subutil
+  - name: lib_utilcode
+    isApply: true
+    useLocal: true
+    localPath: ./lib/utilcode
+    remotePath: 'com.blankj:utilcode:$Config.versionName'
+  - name: lib_utildebug
+    isApply: true
+    useLocal: true
+    localPath: ./lib/utildebug
+  - name: lib_utildebug_no_op
+    isApply: true
+    useLocal: true
+    localPath: ./lib/utildebug-no-op
diff --git a/plugin/api-gradle-plugin/build.gradle b/plugin/api-gradle-plugin/build.gradle
index 2f6b956ee0..8a559c213d 100755
--- a/plugin/api-gradle-plugin/build.gradle
+++ b/plugin/api-gradle-plugin/build.gradle
@@ -6,21 +6,21 @@ apply {
 gradlePlugin {
     plugins {
         apiPlugin {
-            id = 'com.blankj.api'
+            id = Config.plugins.plugin_api.id
             implementationClass = 'com.blankj.api.ApiPlugin'
         }
     }
 }
 
 dependencies {
-    compileOnly Config.depConfig.plugin_gradle.dep
-    implementation Config.depConfig.commons_io.dep
-    implementation Config.depConfig.plugin_lib_base_transform.dep
+    compileOnly Config.plugins.plugin_gradle.path
+    implementation Config.libs.commons_io.path
+    implementation Config.modules.plugin_lib_base_transform.remotePath
     implementation gradleApi()
     implementation localGroovy()
 
-    testImplementation Config.depConfig.test_junit.dep
-    testImplementation Config.depConfig.plugin_gradle.dep
+    testImplementation Config.libs.test_junit.path
+    testImplementation Config.plugins.plugin_gradle.path
 }
 
 sourceSets {
@@ -32,11 +32,9 @@ sourceSets {
 }
 
 ext {
-    groupId = Config.depConfig.plugin_api.groupId
-    artifactId = Config.depConfig.plugin_api.artifactId
-    version = Config.depConfig.plugin_api.version
+    groupId = Config.plugins.plugin_api.groupId
+    artifactId = Config.plugins.plugin_api.artifactId
+    version = Config.plugins.plugin_api.version
     website = "https://github.com/Blankj/AndroidUtilCode"
 }
 apply from: "${rootDir.path}/config/publish.gradle"
-//./gradlew clean :plugin_api-gradle-plugin:mavenLocal     // 上传到本地 mavenLocal
-//./gradlew clean :plugin_api-gradle-plugin:bintrayUpload  // 上传到 jcenter
diff --git a/plugin/buildSrc-plugin/.gitignore b/plugin/buildSrc-plugin/.gitignore
new file mode 100755
index 0000000000..42afabfd2a
--- /dev/null
+++ b/plugin/buildSrc-plugin/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/plugin/buildSrc-plugin/build.gradle b/plugin/buildSrc-plugin/build.gradle
new file mode 100755
index 0000000000..567fbcef2d
--- /dev/null
+++ b/plugin/buildSrc-plugin/build.gradle
@@ -0,0 +1,37 @@
+apply {
+    plugin "groovy"
+    plugin "java-gradle-plugin"
+}
+
+gradlePlugin {
+    plugins {
+        apiPlugin {
+            id = 'com.blankj.buildSrc'
+            implementationClass = 'com.blankj.buildSrc.BuildSrcPlugin'
+        }
+    }
+}
+
+dependencies {
+    compileOnly Config.plugins.plugin_gradle.path
+    implementation Config.libs.commons_io.path
+    implementation gradleApi()
+    implementation localGroovy()
+}
+
+sourceSets {
+    main {
+        groovy {
+            srcDirs += 'src/main/java'
+        }
+    }
+}
+
+ext {
+    groupId = Config.plugins.plugin_buildSrc.groupId
+    artifactId = Config.plugins.plugin_buildSrc.artifactId
+    version = Config.plugins.plugin_buildSrc.version
+    website = "https://github.com/Blankj/AndroidUtilCode"
+}
+apply from: "${rootDir.path}/config/publish.gradle"
+//./gradlew clean plugin:plugin_buildSrc-plugin:publish2Local     // 上传到本地 mavenLocal
diff --git a/plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/BuildSrcPlugin.groovy b/plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/BuildSrcPlugin.groovy
new file mode 100644
index 0000000000..2915b3ffe1
--- /dev/null
+++ b/plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/BuildSrcPlugin.groovy
@@ -0,0 +1,13 @@
+package com.blankj.buildSrc;
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class BuildSrcPlugin implements Plugin {
+
+    @Override
+    void apply(Project project) {
+        println 'apply BuildSrcPlugin'
+        ModuleCfg.main()
+    }
+}
\ No newline at end of file
diff --git a/plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/ModuleCfg.groovy b/plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/ModuleCfg.groovy
new file mode 100644
index 0000000000..d52675d158
--- /dev/null
+++ b/plugin/buildSrc-plugin/src/main/java/com/blankj/buildSrc/ModuleCfg.groovy
@@ -0,0 +1,80 @@
+package com.blankj.buildSrc
+
+import groovy.json.JsonSlurper
+
+
+/**
+ * 在 config.json 中 根据 appConfig 和 pkgConfig 来 include 本地模块
+ * 可以考虑写成插件来更方便 apply
+ */
+
+println 'exe ModuleCfg.groovy'
+
+def config = new JsonSlurper().parse(file("./config.json"))
+
+for (def pro in config.proConfig) {
+    String localPath = pro.localPath
+
+    if (localPath == ":feature:mock") {
+        if (config.pkgConfig.isEmpty()) {
+            pro.isApply = false
+        }
+    } else if (localPath.endsWith(":app")) {
+        def appName = localPath.substring(":feature:".length(), localPath.length() - 4)
+        if (!config.appConfig.contains(appName)) {
+            pro.isApply = false
+        }
+    } else if (localPath.endsWith(":pkg")) {
+        if (!config.pkgConfig.isEmpty()) {
+            def pkgName = localPath.substring(":feature:".length(), localPath.length() - 4)
+            if (!config.pkgConfig.contains(pkgName)) {
+                pro.isApply = false
+            }
+        }
+    }
+
+    if (pro.useLocal && pro.isApply) {
+        def projectPath = ":" + localPath.substring(1).replace(":", "_")
+        include projectPath
+        project(projectPath).projectDir = file(localPath.substring(1).replace(":", "/"))
+    }
+}
+
+def ls = System.getProperty("line.separator")
+
+List proDeps = []
+for (def pro in config.proConfig) {
+    boolean useLocal = pro.useLocal
+    String localPath = pro.localPath
+    String remotePath = pro.remotePath
+    String name = localPath.replace(":", "_").replace("-", "_").substring(1)
+    if (localPath != null) localPath = "\"$localPath\""
+    if (remotePath != null) remotePath = "\"$remotePath\""
+    boolean isApply = pro.isApply
+    proDeps.add(String.format("%-12s%-27s: new DepConfig(%-5s, %-5s, $localPath%s),",
+            "", name, isApply, useLocal, remotePath == null ? "" : ", $remotePath"))
+}
+
+def configFile = file('./buildSrc/src/main/groovy/ModuleConfig.groovy')
+def lines = configFile.readLines("utf8")
+def configContent = new StringBuilder()
+
+boolean enterNeverFlag = false
+for (def line : lines) {
+    if (enterNeverFlag) {
+        if (line.contains("/*Never")) {
+            configContent.append(ls).append(line)
+            enterNeverFlag = false
+        }
+        continue
+    }
+    configContent.append(ls).append(line)
+    if (line.contains("/*Never")) {
+        configContent.append(ls).append(String.format("%-12s/*Generated by \"config.json\"*/", ""))
+        enterNeverFlag = true
+        for (String dep : proDeps) {
+            configContent.append(ls).append(dep)
+        }
+    }
+}
+configFile.write(configContent.substring(ls.length()).toString())
\ No newline at end of file
diff --git a/plugin/bus-gradle-plugin/build.gradle b/plugin/bus-gradle-plugin/build.gradle
index 7cd24042a7..68e43c6867 100755
--- a/plugin/bus-gradle-plugin/build.gradle
+++ b/plugin/bus-gradle-plugin/build.gradle
@@ -6,21 +6,21 @@ apply {
 gradlePlugin {
     plugins {
         busPlugin {
-            id = 'com.blankj.bus'
+            id = Config.plugins.plugin_bus.id
             implementationClass = 'com.blankj.bus.BusPlugin'
         }
     }
 }
 
 dependencies {
-    compileOnly Config.depConfig.plugin_gradle.dep
-    implementation Config.depConfig.commons_io.dep
-    implementation Config.depConfig.plugin_lib_base_transform.dep
+    compileOnly Config.plugins.plugin_gradle.path
+    implementation Config.modules.plugin_lib_base_transform.remotePath
+    implementation Config.libs.commons_io.path
     implementation gradleApi()
     implementation localGroovy()
 
-    testImplementation Config.depConfig.test_junit.dep
-    testImplementation Config.depConfig.plugin_gradle.dep
+    testImplementation Config.libs.test_junit.path
+    testImplementation Config.plugins.plugin_gradle.path
 }
 
 sourceSets {
@@ -32,9 +32,9 @@ sourceSets {
 }
 
 ext {
-    groupId = Config.depConfig.plugin_bus.groupId
-    artifactId = Config.depConfig.plugin_bus.artifactId
-    version = Config.depConfig.plugin_bus.version
+    groupId = Config.plugins.plugin_bus.groupId
+    artifactId = Config.plugins.plugin_bus.artifactId
+    version = Config.plugins.plugin_bus.version
     website = "https://github.com/Blankj/AndroidUtilCode"
 }
 apply from: "${rootDir.path}/config/publish.gradle"
diff --git a/plugin/lib/base-transform/build.gradle b/plugin/lib/base-transform/build.gradle
index 3518481ebd..8eac0ab6d3 100755
--- a/plugin/lib/base-transform/build.gradle
+++ b/plugin/lib/base-transform/build.gradle
@@ -4,8 +4,8 @@ apply {
 }
 
 dependencies {
-    compileOnly Config.depConfig.plugin_gradle.dep
-    implementation Config.depConfig.commons_io.dep
+    compileOnly Config.plugins.plugin_gradle.path
+    implementation Config.libs.commons_io.path
     implementation gradleApi()
     implementation localGroovy()
 }
@@ -19,11 +19,11 @@ sourceSets {
 }
 
 ext {
-    groupId = Config.depConfig.plugin_lib_base_transform.groupId
-    artifactId = Config.depConfig.plugin_lib_base_transform.artifactId
-    version = Config.depConfig.plugin_lib_base_transform.version
+    groupId = Config.modules.plugin_lib_base_transform.groupId
+    artifactId = Config.modules.plugin_lib_base_transform.artifactId
+    version = Config.modules.plugin_lib_base_transform.version
     website = "https://github.com/Blankj/AndroidUtilCode"
 }
 apply from: "${rootDir.path}/config/publish.gradle"
-//./gradlew clean plugin:lib:plugin_lib_base-transform:mavenLocal     // 上传到本地 mavenLocal
-//./gradlew clean plugin:lib:plugin_lib_base-transform:bintrayUpload  // 上传到 gradle 插件库中
+//./gradlew clean :plugin_lib_base-transform:mavenLocal     // 上传到本地 mavenLocal
+//./gradlew clean :plugin_lib_base-transform:bintrayUpload  // 上传到 gradle 插件库中
diff --git a/settings.gradle b/settings.gradle
index 2d1b907aca..3fb2a0a2be 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,73 +1,39 @@
-import groovy.json.JsonSlurper
-
-/**
- * 在 config.json 中 根据 appConfig 和 pkgConfig 来 include 本地模块
- */
-def config = new JsonSlurper().parse(file("./config.json"))
-
-for (def pro in config.proConfig) {
-    String localPath = pro.localPath
-
-    if (localPath == ":feature:mock") {
-        if (config.pkgConfig.isEmpty()) {
-            pro.isApply = false
-        }
-    } else if (localPath.endsWith(":app")) {
-        def appName = localPath.substring(":feature:".length(), localPath.length() - 4)
-        if (!config.appConfig.contains(appName)) {
-            pro.isApply = false
-        }
-    } else if (localPath.endsWith(":pkg")) {
-        if (!config.pkgConfig.isEmpty()) {
-            def pkgName = localPath.substring(":feature:".length(), localPath.length() - 4)
-            if (!config.pkgConfig.contains(pkgName)) {
-                pro.isApply = false
-            }
-        }
-    }
-
-    if (pro.useLocal && pro.isApply) {
-        def projectPath = ":" + localPath.substring(1).replace(":", "_")
-        include projectPath
-        project(projectPath).projectDir = file(localPath.substring(1).replace(":", "/"))
-    }
-}
-
-def ls = System.getProperty("line.separator")
-
-List proDeps = []
-for (def pro in config.proConfig) {
-    boolean useLocal = pro.useLocal
-    String localPath = pro.localPath
-    String remotePath = pro.remotePath
-    String name = localPath.replace(":", "_").replace("-", "_").substring(1)
-    if (localPath != null) localPath = "\"$localPath\""
-    if (remotePath != null) remotePath = "\"$remotePath\""
-    boolean isApply = pro.isApply
-    proDeps.add(String.format("%-12s%-27s: new DepConfig(%-5s, %-5s, $localPath%s),",
-            "", name, isApply, useLocal, remotePath == null ? "" : ", $remotePath"))
-}
-
-def configFile = file('./buildSrc/src/main/groovy/Config.groovy')
-def lines = configFile.readLines("utf8")
-def configContent = new StringBuilder()
-
-boolean enterNeverFlag = false
-for (def line : lines) {
-    if (enterNeverFlag) {
-        if (line.contains("/*Never")) {
-            configContent.append(ls).append(line)
-            enterNeverFlag = false
-        }
-        continue
-    }
-    configContent.append(ls).append(line)
-    if (line.contains("/*Never")) {
-        configContent.append(ls).append(String.format("%-12s/*Generated by \"config.json\"*/", ""))
-        enterNeverFlag = true
-        for (String dep : proDeps) {
-            configContent.append(ls).append(dep)
-        }
-    }
-}
-configFile.write(configContent.substring(ls.length()).toString())
\ No newline at end of file
+//includeBuild 'configPlugin'
+
+//buildscript {
+////    ConfigUtils.init(gradle)
+//    repositories {
+//        mavenLocal()
+//        mavenCentral()
+//    }
+//
+//    dependencies {
+//        classpath 'com.blankj:buildSrc-plugin:1.0'
+//    }
+//}
+
+//apply plugin: "com.blankj.buildSrc"
+
+
+//dependencyResolutionManagement {
+//    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+//    repositories {
+//        google()
+//        mavenCentral()
+//        jcenter() // Warning: this repository is going to shut down soon
+//        maven {url 'https://jetpack.io/'} // Warning: this repository is going to shut down soon
+//    }
+//
+////    configurations.all {
+////        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
+////
+////        resolutionStrategy.eachDependency {
+////            if (it.requested.group == 'com.android.support' && !it.requested.name.contains(
+////                    'multidex')) {
+////                it.useVersion Config.supportVersion
+////            }
+////        }
+////    }
+//}
+
+apply from: 'module_config.gradle'

From d0b890e106be3658d259ca7ec52e232b991f67f1 Mon Sep 17 00:00:00 2001
From: caimengjie 
Date: Mon, 6 Dec 2021 01:45:43 +0800
Subject: [PATCH 40/61] opt: publish v1.31.0

---
 module_config.yaml | 91 ----------------------------------------------
 1 file changed, 91 deletions(-)
 delete mode 100644 module_config.yaml

diff --git a/module_config.yaml b/module_config.yaml
deleted file mode 100644
index b10ce808e6..0000000000
--- a/module_config.yaml
+++ /dev/null
@@ -1,91 +0,0 @@
-desc: 提交 git 时需要检查下配置是否正确!!!
-appConfigDesc: appConfig 配置的是可以跑 app 的模块
-appConfig:
-  - feature_launcher_app
-pkgConfigDesc: pkgConfig 配置的是要依赖的功能包,为空则依赖全部
-pkgConfig: [ ]
-moduleConfigDesc: moduleConfig 配置的是使用本地还是仓库,优先级低于 appConfig 和 pkgConfig
-moduleConfig:
-  - name: plugin_api_gradle_plugin
-      isApply: true
-      useLocal: true
-      localPath: ./plugin/api-gradle-plugin
-  - name: plugin_bus_gradle_plugin
-    isApply: true
-    useLocal: true
-    localPath: ./plugin/bus-gradle-plugin
-  - name: plugin_lib_base_transform
-    isApply: true
-    useLocal: true
-    localPath: ./plugin/lib/base-transform
-    remotePath: 'com.blankj:base-transform:1.0'
-  - name: plugin_buildSrc_plugin
-    isApply: true
-    useLocal: true
-    localPath: ./plugin/buildSrc-plugin
-  - name: feature_mock
-    isApply: true
-    useLocal: true
-    localPath: ./feature/mock
-  - name: feature_launcher_app
-    isApply: true
-    useLocal: true
-    localPath: ./feature/launcher/app
-  - name: feature_main_app
-    isApply: true
-    useLocal: true
-    localPath: ./feature/main/app
-  - name: feature_main_pkg
-    isApply: true
-    useLocal: true
-    localPath: ./feature/main/pkg
-  - name: feature_subutil_app
-    isApply: true
-    useLocal: true
-    localPath: ./feature/subutil/app
-  - name: feature_subutil_pkg
-    isApply: true
-    useLocal: true
-    localPath: ./feature/subutil/pkg
-  - name: feature_subutil_export
-    isApply: true
-    useLocal: true
-    localPath: ./feature/subutil/export
-  - name: feature_utilcode_app
-    isApply: true
-    useLocal: true
-    localPath: ./feature/utilcode/app
-  - name: feature_utilcode_pkg
-    isApply: true
-    useLocal: true
-    localPath: ./feature/utilcode/pkg
-  - name: feature_utilcode_export
-    isApply: true
-    useLocal: true
-    localPath: ./feature/utilcode/export
-    remotePath: 'com.blankj:utilcode-export:1.1'
-  - name: lib_base
-    isApply: true
-    useLocal: true
-    localPath: ./lib/base
-  - name: lib_common
-    isApply: true
-    useLocal: true
-    localPath: ./lib/common
-  - name: lib_subutil
-    isApply: true
-    useLocal: true
-    localPath: ./lib/subutil
-  - name: lib_utilcode
-    isApply: true
-    useLocal: true
-    localPath: ./lib/utilcode
-    remotePath: 'com.blankj:utilcode:$Config.versionName'
-  - name: lib_utildebug
-    isApply: true
-    useLocal: true
-    localPath: ./lib/utildebug
-  - name: lib_utildebug_no_op
-    isApply: true
-    useLocal: true
-    localPath: ./lib/utildebug-no-op

From ccba200fd83bc6479b8b8065a4824cd0e5fd67c2 Mon Sep 17 00:00:00 2001
From: caimengjie 
Date: Mon, 6 Dec 2021 01:47:28 +0800
Subject: [PATCH 41/61] opt: publish v1.31.0

---
 CHANGELOG.md                                   |  1 +
 buildSrc/src/main/groovy/Config.groovy         |  2 +-
 config/publish.gradle                          |  8 ++++++--
 lib/utilcode/README-CN.md                      |  7 ++++---
 lib/utilcode/README.md                         |  7 ++++---
 .../com/blankj/utilcode/util/AppUtils.java     | 18 +++++++++---------
 .../com/blankj/utilcode/util/NetworkUtils.java |  5 +++--
 .../com/blankj/utilcode/util/TimeUtils.java    |  2 ++
 module_config.json                             |  2 +-
 9 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 401a5071f8..c4bcc19c85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,4 @@
+* `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.
diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index 4a0b27a980..2465570d82 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -34,7 +34,7 @@ class Config {
             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: false, localPath: "./lib/utilcode", remotePath: "com.blankj:utilcode:$Config.versionName"),
+            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*/
diff --git a/config/publish.gradle b/config/publish.gradle
index fa8a449f3c..91f749a86d 100644
--- a/config/publish.gradle
+++ b/config/publish.gradle
@@ -220,6 +220,10 @@ static def isAndroidEnv(Project project) {
     return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
 }
 
-task publish2Local(type: GradleBuild, dependsOn: ['clean', 'assemble', 'publishReleasePublicationToMavenLocal']) {}
+task publish2Local(type: GradleBuild) {
+    tasks = ['assemble', 'publishReleasePublicationToMavenLocal']
+}
 
-task publish2Remote(type: GradleBuild, dependsOn: ['clean', 'assemble', 'publishReleasePublicationToMavenRepository']) {}
\ No newline at end of file
+task publish2Remote(type: GradleBuild) {
+    tasks = ['assemble', 'publishReleasePublicationToMavenRepository']
+}
\ No newline at end of file
diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
index 79b18eef15..0e4e93f3a0 100644
--- a/lib/utilcode/README-CN.md
+++ b/lib/utilcode/README-CN.md
@@ -2,10 +2,11 @@
 
 Gradle:
 ```groovy
-implementation 'com.blankj:utilcode:1.30.6'
-
 // if u use AndroidX, use the following
-implementation 'com.blankj:utilcodex:1.30.6'
+implementation 'com.blankj:utilcodex:1.31.0'
+
+// Not in maintenance
+implementation 'com.blankj:utilcode:1.30.6'
 ```
 
 
diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md
index 63f7a83ba7..cdabfba45a 100644
--- a/lib/utilcode/README.md
+++ b/lib/utilcode/README.md
@@ -2,10 +2,11 @@
 
 Gradle:
 ```groovy
-implementation 'com.blankj:utilcode:1.30.6'
-
 // if u use AndroidX, use the following
-implementation 'com.blankj:utilcodex:1.30.6'
+implementation 'com.blankj:utilcodex:1.31.0'
+
+// Not in maintenance
+implementation 'com.blankj:utilcode:1.30.6'
 ```
 
 
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 fe8301f9ec..8f03e1cf1f 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
@@ -385,16 +385,16 @@ 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(){
+    public static boolean isFirstTimeInstall() {
         try {
-            Long firstInstallTime = Utils.getApp().getPackageManager().getPackageInfo(this.getAppPackageName(), 0).firstInstallTime;
-            Long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(this.getAppPackageName(), 0).lastUpdateTime;
+            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;
@@ -406,17 +406,17 @@ public static boolean isFirstTimeInstall(){
      *
      * @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(){
+    public static boolean isAppUpgraded() {
         try {
-            Long firstInstallTime = Utils.getApp().getPackageManager().getPackageInfo(this.getAppPackageName(), 0).firstInstallTime;
-            Long lastUpdateTime = Utils.getApp().getPackageManager().getPackageInfo(this.getAppPackageName(), 0).lastUpdateTime;
+            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.
      *
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 b2c64a6416..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,6 +6,7 @@
 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;
@@ -280,9 +281,9 @@ public static boolean isBehindProxy(){
     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()
+            return cm.getNetworkInfo(ConnectivityManager.TYPE_VPN).isConnectedOrConnecting();
         } else {
-            return cm.getNetworkInfo(NetworkCapabilities.TRANSPORT_VPN).isConnectedOrConnecting()
+            return cm.getNetworkInfo(NetworkCapabilities.TRANSPORT_VPN).isConnectedOrConnecting();
         }
     }
 
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java
index 8a38efd195..ee700cbeb7 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/TimeUtils.java
@@ -1,6 +1,8 @@
 package com.blankj.utilcode.util;
 
 import android.annotation.SuppressLint;
+import android.os.Build;
+import android.provider.Settings;
 
 import com.blankj.utilcode.constant.TimeConstants;
 
diff --git a/module_config.json b/module_config.json
index 18f416382a..87233122b9 100644
--- a/module_config.json
+++ b/module_config.json
@@ -23,7 +23,7 @@
     {"name": "lib_base",                  "isApply": true, "useLocal": true, "localPath": "./lib/base"},
     {"name": "lib_common",                "isApply": true, "useLocal": true, "localPath": "./lib/common"},
     {"name": "lib_subutil",               "isApply": true, "useLocal": true, "localPath": "./lib/subutil"},
-    {"name": "lib_utilcode",              "isApply": true, "useLocal": false, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"},
+    {"name": "lib_utilcode",              "isApply": true, "useLocal": true, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"},
     {"name": "lib_utildebug",             "isApply": true, "useLocal": true, "localPath": "./lib/utildebug"},
     {"name": "lib_utildebug_no_op",       "isApply": true, "useLocal": true, "localPath": "./lib/utildebug-no-op"}
   ]

From ac872f8fb52d569d252e5fe136b0f7af14798f5a Mon Sep 17 00:00:00 2001
From: caimengjie 
Date: Mon, 6 Dec 2021 01:51:47 +0800
Subject: [PATCH 42/61] fix: ci

---
 buildSrc/src/main/groovy/Config.groovy |  4 ++--
 config/publish.gradle                  | 15 ++++++---------
 module_config.json                     |  2 +-
 3 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index 2465570d82..268ec666ce 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -34,7 +34,7 @@ class Config {
             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_utilcode               : new ModuleConfig(isApply: true , useLocal: false, 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*/
@@ -54,7 +54,7 @@ class Config {
             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: true, useLocal: false, path: "com.blankj:buildSrc-plugin:1.0", id: "com.blankj.buildSrc"),
+            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
     ]
diff --git a/config/publish.gradle b/config/publish.gradle
index 91f749a86d..7608215123 100644
--- a/config/publish.gradle
+++ b/config/publish.gradle
@@ -27,17 +27,14 @@ apply plugin: 'signing'
 ext.multiPublishMode = true
 
 File localPropertiesFile = project.rootProject.file("local.properties");
-if (localPropertiesFile.exists()) {
-    Properties properties = new Properties()
-    properties.load(new FileInputStream(localPropertiesFile))
-    properties.each { name, value -> ext[name] = value }
-} else {
-    if (!ext["signing.keyId"] && !ext["signing.password"] && !ext["signing.secretKeyRingFile"]
-            && !ext["ossrhUsername"] && !ext["ossrhPassword"]) {
-        throw new NullPointerException("U should set MavenCentral params in local.properties")
-    }
+if (!localPropertiesFile.exists()) {
+    return
 }
 
+Properties properties = new Properties()
+properties.load(new FileInputStream(localPropertiesFile))
+properties.each { name, value -> ext[name] = value }
+
 afterEvaluate {
     def ext = project.ext
     publishing {
diff --git a/module_config.json b/module_config.json
index 87233122b9..18f416382a 100644
--- a/module_config.json
+++ b/module_config.json
@@ -23,7 +23,7 @@
     {"name": "lib_base",                  "isApply": true, "useLocal": true, "localPath": "./lib/base"},
     {"name": "lib_common",                "isApply": true, "useLocal": true, "localPath": "./lib/common"},
     {"name": "lib_subutil",               "isApply": true, "useLocal": true, "localPath": "./lib/subutil"},
-    {"name": "lib_utilcode",              "isApply": true, "useLocal": true, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"},
+    {"name": "lib_utilcode",              "isApply": true, "useLocal": false, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"},
     {"name": "lib_utildebug",             "isApply": true, "useLocal": true, "localPath": "./lib/utildebug"},
     {"name": "lib_utildebug_no_op",       "isApply": true, "useLocal": true, "localPath": "./lib/utildebug-no-op"}
   ]

From f9a1dbf0dfa8ad5bd20fe4f72bb72a4470b248db Mon Sep 17 00:00:00 2001
From: Absinthe 
Date: Sat, 11 Dec 2021 11:59:28 +0800
Subject: [PATCH 43/61] Explicitly specify `android:exported` to make
 compatible with Android 12.

---
 lib/utilcode/src/main/AndroidManifest.xml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/utilcode/src/main/AndroidManifest.xml b/lib/utilcode/src/main/AndroidManifest.xml
index fc5b75e0e3..d45dd57787 100644
--- a/lib/utilcode/src/main/AndroidManifest.xml
+++ b/lib/utilcode/src/main/AndroidManifest.xml
@@ -5,12 +5,14 @@
 
         
 
         
Date: Wed, 25 May 2022 11:18:02 +0800
Subject: [PATCH 44/61] fix bug

---
 lib/utilcode/src/main/res/xml/util_code_provider_paths.xml | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml b/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml
index ed731a2299..b88716480c 100644
--- a/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml
+++ b/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml
@@ -23,4 +23,9 @@
     
-
\ No newline at end of file
+      
+    
+

From 8dc01389ee5599c44c7ae26a8c26411b63bfa564 Mon Sep 17 00:00:00 2001
From: Justson 
Date: Wed, 8 Jun 2022 10:55:22 +0800
Subject: [PATCH 45/61] Update README-CN.md

---
 lib/utilcode/README-CN.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
index 0e4e93f3a0..260cabac24 100644
--- a/lib/utilcode/README-CN.md
+++ b/lib/utilcode/README-CN.md
@@ -6,7 +6,7 @@ Gradle:
 implementation 'com.blankj:utilcodex:1.31.0'
 
 // Not in maintenance
-implementation 'com.blankj:utilcode:1.30.6'
+implementation 'com.blankj:utilcode:1.30.7'
 ```
 
 

From ed848ebd638507a492946e6300b057fb621b5dba Mon Sep 17 00:00:00 2001
From: NH002 
Date: Thu, 9 Jun 2022 09:06:11 +0200
Subject: [PATCH 46/61] Added uri2FileNoCacheCopy

---
 .../main/java/com/blankj/utilcode/util/UriUtils.java  | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UriUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UriUtils.java
index 322b9d1190..c22d1bba38 100644
--- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/UriUtils.java
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/UriUtils.java
@@ -77,6 +77,17 @@ public static File uri2File(final Uri uri) {
         return copyUri2Cache(uri);
     }
 
+    /**
+     * Uri to file, without creating the cache copy if the path cannot be resolved.
+     *
+     * @param uri The uri.
+     * @return file
+     */
+    public static File uri2FileNoCacheCopy(final Uri uri) {
+        if (uri == null) return null;
+        return uri2FileReal(uri);
+    }
+    
     /**
      * Uri to file.
      *

From da8b04946981398dfb217825946af55cba3b3444 Mon Sep 17 00:00:00 2001
From: taochen <935612713@qq.com>
Date: Mon, 18 Jul 2022 16:12:33 +0800
Subject: [PATCH 47/61] =?UTF-8?q?[M]=20BarUtils=E6=B7=BB=E5=8A=A0transpare?=
 =?UTF-8?q?ntNavBar=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../pkg/feature/bar/nav/BarNavActivity.kt     | 42 +++++++++++++------
 .../com/blankj/utilcode/util/BarUtils.java    | 32 +++++++++++---
 2 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
index 1b3032974f..48a738ecd7 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
@@ -12,7 +12,6 @@ import com.blankj.utilcode.pkg.R
 import com.blankj.utilcode.util.BarUtils
 import com.blankj.utilcode.util.CollectionUtils
 import com.blankj.utilcode.util.ColorUtils
-import com.blankj.utilcode.util.Utils
 
 /**
  * ```
@@ -41,24 +40,43 @@ class BarNavActivity : CommonActivity() {
             add(CommonItemTitle("isSupportNavBar", BarUtils.isSupportNavBar().toString()))
             if (BarUtils.isSupportNavBar()) {
                 add(CommonItemSwitch(
-                        R.string.bar_nav_visibility,
-                        { BarUtils.isNavBarVisible(this@BarNavActivity) },
-                        { BarUtils.setNavBarVisibility(this@BarNavActivity, it) }
+                    R.string.bar_nav_visibility,
+                    { BarUtils.isNavBarVisible(this@BarNavActivity) },
+                    { BarUtils.setNavBarVisibility(this@BarNavActivity, it) }
                 ))
 
                 add(CommonItemSwitch(
-                        R.string.bar_nav_light_mode,
-                        { BarUtils.isNavBarLightMode(this@BarNavActivity) },
-                        { BarUtils.setNavBarLightMode(this@BarNavActivity, it) }
+                    R.string.bar_nav_light_mode,
+                    { BarUtils.isNavBarLightMode(this@BarNavActivity) },
+                    { BarUtils.setNavBarLightMode(this@BarNavActivity, it) }
                 ))
 
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-                    add(CommonItemClick("getNavBarColor: ${ColorUtils.int2ArgbString(BarUtils.getNavBarColor(this@BarNavActivity))}").setOnItemClickListener() { _, item, _ ->
-                        BarUtils.setNavBarColor(this@BarNavActivity, ColorUtils.getRandomColor())
-                        itemsView.updateItems(bindItems())
-                        item.title = "getNavBarColor: ${ColorUtils.int2ArgbString(BarUtils.getNavBarColor(this@BarNavActivity))}"
-                    })
+                    add(
+                        CommonItemClick(
+                            "getNavBarColor: ${
+                                ColorUtils.int2ArgbString(
+                                    BarUtils.getNavBarColor(
+                                        this@BarNavActivity
+                                    )
+                                )
+                            }"
+                        ).setOnItemClickListener() { _, item, _ ->
+                            BarUtils.setNavBarColor(
+                                this@BarNavActivity,
+                                ColorUtils.getRandomColor()
+                            )
+                            itemsView.updateItems(bindItems())
+                            item.title = "getNavBarColor: ${
+                                ColorUtils.int2ArgbString(
+                                    BarUtils.getNavBarColor(this@BarNavActivity)
+                                )
+                            }"
+                        })
                 }
+                add(CommonItemClick("transparentNavBar").setOnItemClickListener() { _, item, _ ->
+                    BarUtils.transparentNavBar(this@BarNavActivity)
+                })
             }
         }
     }
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 af9dbc4fcd..ece4f7faba 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;
@@ -19,15 +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;
 
 /**
  * 
@@ -44,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...");
@@ -715,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);
+    }
 }

From 0a1be7ec672053012b2bdae6259037765ff0af14 Mon Sep 17 00:00:00 2001
From: taochen <935612713@qq.com>
Date: Mon, 18 Jul 2022 17:02:24 +0800
Subject: [PATCH 48/61] =?UTF-8?q?[M]=20=E4=BF=AE=E6=94=B9BarUtils=E6=96=B9?=
 =?UTF-8?q?=E6=B3=95=E5=88=97=E8=A1=A8=E5=8F=8A=E6=8F=8F=E8=BF=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/utilcode/README-CN.md | 1 +
 lib/utilcode/README.md    | 1 +
 2 files changed, 2 insertions(+)

diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
index 0e4e93f3a0..f7523783f9 100644
--- a/lib/utilcode/README-CN.md
+++ b/lib/utilcode/README-CN.md
@@ -141,6 +141,7 @@ getNavBarColor                       : 获取导航栏颜色
 isSupportNavBar                      : 判断是否支持导航栏
 setNavBarLightMode                   : 设置导航栏是否为浅色模式
 isNavBarLightMode                    : 判断导航栏是否为浅色模式
+transparentNavBar                    : 透明导航栏
 ```
 
 * ### 亮度相关 -> [BrightnessUtils.java][brightness.java] -> [Demo][brightness.demo]
diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md
index cdabfba45a..9d2025ebb0 100644
--- a/lib/utilcode/README.md
+++ b/lib/utilcode/README.md
@@ -140,6 +140,7 @@ getNavBarColor
 isSupportNavBar
 setNavBarLightMode
 isNavBarLightMode
+transparentNavBar
 ```
 
 * ### About Brightness -> [BrightnessUtils.java][brightness.java] -> [Demo][brightness.demo]

From cf983059a82e0306ea1bdaa773f9fec0ed03ad22 Mon Sep 17 00:00:00 2001
From: taochen <935612713@qq.com>
Date: Tue, 19 Jul 2022 12:00:46 +0800
Subject: [PATCH 49/61] =?UTF-8?q?[F]=20TargetSdkVersion=2030=20AppUtils.is?=
 =?UTF-8?q?AppInstalled=E8=BF=94=E5=9B=9E=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/utilcode/src/main/AndroidManifest.xml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/utilcode/src/main/AndroidManifest.xml b/lib/utilcode/src/main/AndroidManifest.xml
index fc5b75e0e3..4d2b38e471 100644
--- a/lib/utilcode/src/main/AndroidManifest.xml
+++ b/lib/utilcode/src/main/AndroidManifest.xml
@@ -1,6 +1,15 @@
 
 
+    
+        
+            
+        
+        
+            
+        
+    
+
     
 
         
Date: Tue, 19 Jul 2022 17:31:46 +0800
Subject: [PATCH 50/61] =?UTF-8?q?[M]=20AppUtils=E5=A2=9E=E5=8A=A0getAppMin?=
 =?UTF-8?q?SdkVersion,=20getAppTargetSdkVersion=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../utilcode/pkg/feature/app/AppActivity.kt   | 108 ++++++++--------
 lib/utilcode/README-CN.md                     |   2 +
 lib/utilcode/README.md                        |   2 +
 .../com/blankj/utilcode/util/AppUtils.java    | 115 ++++++++++++++++--
 .../debug/tool/appInfo/AppInfoItem.java       |  15 ++-
 5 files changed, 173 insertions(+), 69 deletions(-)

diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
index 175fa1bc3b..21eb351146 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
@@ -54,7 +54,10 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
 
     override fun bindItems(): MutableList> {
         return CollectionUtils.newArrayList(
-                CommonItemSwitch("registerAppStatusChangedListener", { isRegisterAppStatusChangedListener }, {
+            CommonItemSwitch(
+                "registerAppStatusChangedListener",
+                { isRegisterAppStatusChangedListener },
+                {
                     isRegisterAppStatusChangedListener = it
                     if (it) {
                         AppUtils.registerAppStatusChangedListener(this)
@@ -62,55 +65,63 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
                         AppUtils.unregisterAppStatusChangedListener(this)
                     }
                 }),
-                CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()),
-                CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()),
-                CommonItemTitle("isAppSystem", AppUtils.isAppSystem().toString()),
-                CommonItemTitle("isAppForeground", AppUtils.isAppForeground(AppUtils.getAppPackageName()).toString()),
-                CommonItemTitle("isAppRunning", AppUtils.isAppRunning(AppUtils.getAppPackageName()).toString()),
-                CommonItemImage("getAppIcon") {
-                    it.setImageDrawable(AppUtils.getAppIcon())
-                },
-                CommonItemTitle("getAppPackageName", AppUtils.getAppPackageName()),
-                CommonItemTitle("getAppName", AppUtils.getAppName()),
-                CommonItemTitle("getAppPath", AppUtils.getAppPath()),
-                CommonItemTitle("getAppVersionName", AppUtils.getAppVersionName()),
-                CommonItemTitle("getAppVersionCode", AppUtils.getAppVersionCode().toString()),
-                CommonItemTitle("getAppSignaturesSHA1", AppUtils.getAppSignaturesSHA1().toString()),
-                CommonItemTitle("getAppSignaturesSHA256", AppUtils.getAppSignaturesSHA256().toString()),
-                CommonItemTitle("getAppSignaturesMD5", AppUtils.getAppSignaturesMD5().toString()),
-                CommonItemTitle("getAppUid", AppUtils.getAppUid().toString()),
-                CommonItemTitle("getApkInfo", AppUtils.getApkInfo(AppUtils.getAppPath()).toString()),
-
-                CommonItemClick(R.string.app_install) {
-                    if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
-                        ToastUtils.showShort(R.string.app_install_tips)
+            CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()),
+            CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()),
+            CommonItemTitle("isAppSystem", AppUtils.isAppSystem().toString()),
+            CommonItemTitle(
+                "isAppForeground",
+                AppUtils.isAppForeground(AppUtils.getAppPackageName()).toString()
+            ),
+            CommonItemTitle(
+                "isAppRunning",
+                AppUtils.isAppRunning(AppUtils.getAppPackageName()).toString()
+            ),
+            CommonItemImage("getAppIcon") {
+                it.setImageDrawable(AppUtils.getAppIcon())
+            },
+            CommonItemTitle("getAppPackageName", AppUtils.getAppPackageName()),
+            CommonItemTitle("getAppName", AppUtils.getAppName()),
+            CommonItemTitle("getAppPath", AppUtils.getAppPath()),
+            CommonItemTitle("getAppVersionName", AppUtils.getAppVersionName()),
+            CommonItemTitle("getAppVersionCode", AppUtils.getAppVersionCode().toString()),
+            CommonItemTitle("getAppMinSdkVersion", AppUtils.getAppMinSdkVersion().toString()),
+            CommonItemTitle("getAppTargetSdkVersion", AppUtils.getAppTargetSdkVersion().toString()),
+            CommonItemTitle("getAppSignaturesSHA1", AppUtils.getAppSignaturesSHA1().toString()),
+            CommonItemTitle("getAppSignaturesSHA256", AppUtils.getAppSignaturesSHA256().toString()),
+            CommonItemTitle("getAppSignaturesMD5", AppUtils.getAppSignaturesMD5().toString()),
+            CommonItemTitle("getAppUid", AppUtils.getAppUid().toString()),
+            CommonItemTitle("getApkInfo", AppUtils.getApkInfo(AppUtils.getAppPath()).toString()),
+
+            CommonItemClick(R.string.app_install) {
+                if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
+                    ToastUtils.showShort(R.string.app_install_tips)
+                } else {
+                    if (!FileUtils.isFileExists(Config.TEST_APK_PATH)) {
+                        ReleaseInstallApkTask(listener).execute()
                     } else {
-                        if (!FileUtils.isFileExists(Config.TEST_APK_PATH)) {
-                            ReleaseInstallApkTask(listener).execute()
-                        } else {
-                            listener.onReleased()
-                        }
+                        listener.onReleased()
                     }
-                },
-                CommonItemClick(R.string.app_uninstall) {
-                    if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
-                        AppUtils.uninstallApp(Config.TEST_PKG)
-                    } else {
-                        ToastUtils.showShort(R.string.app_uninstall_tips)
-                    }
-                },
-                CommonItemClick(R.string.app_launch) {
-                    AppUtils.launchApp(this.packageName)
-                },
-                CommonItemClick(R.string.app_relaunch) {
-                    AppUtils.relaunchApp()
-                },
-                CommonItemClick(R.string.app_launch_details_settings, true) {
-                    AppUtils.launchAppDetailsSettings()
-                },
-                CommonItemClick(R.string.app_exit) {
-                    AppUtils.exitApp()
                 }
+            },
+            CommonItemClick(R.string.app_uninstall) {
+                if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
+                    AppUtils.uninstallApp(Config.TEST_PKG)
+                } else {
+                    ToastUtils.showShort(R.string.app_uninstall_tips)
+                }
+            },
+            CommonItemClick(R.string.app_launch) {
+                AppUtils.launchApp(this.packageName)
+            },
+            CommonItemClick(R.string.app_relaunch) {
+                AppUtils.relaunchApp()
+            },
+            CommonItemClick(R.string.app_launch_details_settings, true) {
+                AppUtils.launchAppDetailsSettings()
+            },
+            CommonItemClick(R.string.app_exit) {
+                AppUtils.exitApp()
+            }
         )
     }
 
@@ -130,7 +141,8 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
     }
 }
 
-class ReleaseInstallApkTask(private val mListener: OnReleasedListener) : ThreadUtils.SimpleTask() {
+class ReleaseInstallApkTask(private val mListener: OnReleasedListener) :
+    ThreadUtils.SimpleTask() {
 
     override fun doInBackground() {
         ResourceUtils.copyFileFromAssets("test_install", Config.TEST_APK_PATH)
diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
index f7523783f9..641e96ff1d 100644
--- a/lib/utilcode/README-CN.md
+++ b/lib/utilcode/README-CN.md
@@ -72,6 +72,8 @@ getAppName                        : 获取 App 名称
 getAppPath                        : 获取 App 路径
 getAppVersionName                 : 获取 App 版本号
 getAppVersionCode                 : 获取 App 版本码
+getAppMinSdkVersion               : 获取 App 支持最低系统版本号
+getAppTargetSdkVersion            : 获取 App 目标系统版本号
 getAppSignatures                  : 获取 App 签名
 getAppSignaturesSHA1              : 获取应用签名的的 SHA1 值
 getAppSignaturesSHA256            : 获取应用签名的的 SHA256 值
diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md
index 9d2025ebb0..b88bcbcfbd 100644
--- a/lib/utilcode/README.md
+++ b/lib/utilcode/README.md
@@ -72,6 +72,8 @@ getAppName
 getAppPath
 getAppVersionName
 getAppVersionCode
+getAppMinSdkVersion
+getAppTargetSdkVersion
 getAppSignatures
 getAppSignaturesSHA1
 getAppSignaturesSHA256
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 8f03e1cf1f..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
@@ -14,13 +14,13 @@
 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;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 /**
  * 
  *     author: Blankj
@@ -541,6 +541,65 @@ 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.
      *
@@ -721,6 +780,8 @@ private static List getAppSignaturesHash(final String packageName, final
      * 
  • path of package
  • *
  • version name
  • *
  • version code
  • + *
  • minimum sdk version code
  • + *
  • target sdk version code
  • *
  • is system
  • * * @@ -740,6 +801,8 @@ public static AppInfo getAppInfo() { *
  • path of package
  • *
  • version name
  • *
  • version code
  • + *
  • minimum sdk version code
  • + *
  • target sdk version code
  • *
  • is system
  • * * @@ -829,13 +892,18 @@ private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) { String packageName = pi.packageName; ApplicationInfo ai = pi.applicationInfo; if (ai == null) { - return new AppInfo(packageName, "", null, "", versionName, versionCode, false); + 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; + 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); } /** @@ -843,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; @@ -907,14 +977,31 @@ 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); } @@ -928,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/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java b/lib/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java index 76351e4b10..54895ee71f 100644 --- a/lib/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java +++ b/lib/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java @@ -5,10 +5,12 @@ import android.view.View.OnClickListener; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; + import com.blankj.utilcode.util.AppUtils; import com.blankj.utilcode.util.ClickUtils; import com.blankj.utilcode.util.StringUtils; -import com.blankj.utildebug.DebugUtils; import com.blankj.utildebug.R; import com.blankj.utildebug.base.rv.BaseItem; import com.blankj.utildebug.base.rv.ItemViewHolder; @@ -16,9 +18,6 @@ import java.util.ArrayList; import java.util.List; -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - /** *
      *     author: blankj
    @@ -29,8 +28,8 @@
      */
     public class AppInfoItem extends BaseItem {
     
    -    private String          mTitle;
    -    private String          mContent;
    +    private String mTitle;
    +    private String mContent;
         private OnClickListener mListener;
     
         private TextView titleTv;
    @@ -71,9 +70,9 @@ public static List getAppInfoItems() {
             appInfoItems.add(new AppInfoItem(R.string.du_app_info_version_name, AppUtils.getAppVersionName()));
             appInfoItems.add(new AppInfoItem(R.string.du_app_info_version_code, String.valueOf(AppUtils.getAppVersionCode())));
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    -            appInfoItems.add(new AppInfoItem(R.string.du_app_info_min_sdk_version, String.valueOf(DebugUtils.getApp().getApplicationInfo().minSdkVersion)));
    +            appInfoItems.add(new AppInfoItem(R.string.du_app_info_min_sdk_version, String.valueOf(AppUtils.getAppMinSdkVersion())));
             }
    -        appInfoItems.add(new AppInfoItem(R.string.du_app_info_target_sdk_version, String.valueOf(DebugUtils.getApp().getApplicationInfo().targetSdkVersion)));
    +        appInfoItems.add(new AppInfoItem(R.string.du_app_info_target_sdk_version, String.valueOf(AppUtils.getAppTargetSdkVersion())));
             appInfoItems.add(new AppInfoItem(R.string.du_app_info_open_app_info_page, "", new OnClickListener() {
                 @Override
                 public void onClick(View v) {
    
    From 718f281a3da9d4e4e6c3298faf4da9e4563e7d50 Mon Sep 17 00:00:00 2001
    From: taochen <935612713@qq.com>
    Date: Mon, 18 Jul 2022 16:12:33 +0800
    Subject: [PATCH 51/61] =?UTF-8?q?[M]=20BarUtils=E6=B7=BB=E5=8A=A0transpare?=
     =?UTF-8?q?ntNavBar=E5=AE=9E=E7=8E=B0?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     .../pkg/feature/bar/nav/BarNavActivity.kt     | 42 +++++++++++++------
     .../com/blankj/utilcode/util/BarUtils.java    | 32 +++++++++++---
     2 files changed, 57 insertions(+), 17 deletions(-)
    
    diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
    index 1b3032974f..48a738ecd7 100644
    --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
    +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
    @@ -12,7 +12,6 @@ import com.blankj.utilcode.pkg.R
     import com.blankj.utilcode.util.BarUtils
     import com.blankj.utilcode.util.CollectionUtils
     import com.blankj.utilcode.util.ColorUtils
    -import com.blankj.utilcode.util.Utils
     
     /**
      * ```
    @@ -41,24 +40,43 @@ class BarNavActivity : CommonActivity() {
                 add(CommonItemTitle("isSupportNavBar", BarUtils.isSupportNavBar().toString()))
                 if (BarUtils.isSupportNavBar()) {
                     add(CommonItemSwitch(
    -                        R.string.bar_nav_visibility,
    -                        { BarUtils.isNavBarVisible(this@BarNavActivity) },
    -                        { BarUtils.setNavBarVisibility(this@BarNavActivity, it) }
    +                    R.string.bar_nav_visibility,
    +                    { BarUtils.isNavBarVisible(this@BarNavActivity) },
    +                    { BarUtils.setNavBarVisibility(this@BarNavActivity, it) }
                     ))
     
                     add(CommonItemSwitch(
    -                        R.string.bar_nav_light_mode,
    -                        { BarUtils.isNavBarLightMode(this@BarNavActivity) },
    -                        { BarUtils.setNavBarLightMode(this@BarNavActivity, it) }
    +                    R.string.bar_nav_light_mode,
    +                    { BarUtils.isNavBarLightMode(this@BarNavActivity) },
    +                    { BarUtils.setNavBarLightMode(this@BarNavActivity, it) }
                     ))
     
                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    -                    add(CommonItemClick("getNavBarColor: ${ColorUtils.int2ArgbString(BarUtils.getNavBarColor(this@BarNavActivity))}").setOnItemClickListener() { _, item, _ ->
    -                        BarUtils.setNavBarColor(this@BarNavActivity, ColorUtils.getRandomColor())
    -                        itemsView.updateItems(bindItems())
    -                        item.title = "getNavBarColor: ${ColorUtils.int2ArgbString(BarUtils.getNavBarColor(this@BarNavActivity))}"
    -                    })
    +                    add(
    +                        CommonItemClick(
    +                            "getNavBarColor: ${
    +                                ColorUtils.int2ArgbString(
    +                                    BarUtils.getNavBarColor(
    +                                        this@BarNavActivity
    +                                    )
    +                                )
    +                            }"
    +                        ).setOnItemClickListener() { _, item, _ ->
    +                            BarUtils.setNavBarColor(
    +                                this@BarNavActivity,
    +                                ColorUtils.getRandomColor()
    +                            )
    +                            itemsView.updateItems(bindItems())
    +                            item.title = "getNavBarColor: ${
    +                                ColorUtils.int2ArgbString(
    +                                    BarUtils.getNavBarColor(this@BarNavActivity)
    +                                )
    +                            }"
    +                        })
                     }
    +                add(CommonItemClick("transparentNavBar").setOnItemClickListener() { _, item, _ ->
    +                    BarUtils.transparentNavBar(this@BarNavActivity)
    +                })
                 }
             }
         }
    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 af9dbc4fcd..ece4f7faba 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;
    @@ -19,15 +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;
     
     /**
      * 
    @@ -44,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...");
    @@ -715,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);
    +    }
     }
    
    From afaea3eb6b29d24c18cfbcb4a103310fd380b16e Mon Sep 17 00:00:00 2001
    From: Justson 
    Date: Wed, 8 Jun 2022 10:55:22 +0800
    Subject: [PATCH 52/61] Update README-CN.md
    
    ---
     lib/utilcode/README-CN.md | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
    index 0e4e93f3a0..260cabac24 100644
    --- a/lib/utilcode/README-CN.md
    +++ b/lib/utilcode/README-CN.md
    @@ -6,7 +6,7 @@ Gradle:
     implementation 'com.blankj:utilcodex:1.31.0'
     
     // Not in maintenance
    -implementation 'com.blankj:utilcode:1.30.6'
    +implementation 'com.blankj:utilcode:1.30.7'
     ```
     
     
    
    From 555cca99df44edc2025db0a3cbe9dc1b4b65db31 Mon Sep 17 00:00:00 2001
    From: sth0409 <97033765@qq.com>
    Date: Wed, 25 May 2022 11:18:02 +0800
    Subject: [PATCH 53/61] fix bug
    
    ---
     lib/utilcode/src/main/res/xml/util_code_provider_paths.xml | 7 ++++++-
     1 file changed, 6 insertions(+), 1 deletion(-)
    
    diff --git a/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml b/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml
    index ed731a2299..b88716480c 100644
    --- a/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml
    +++ b/lib/utilcode/src/main/res/xml/util_code_provider_paths.xml
    @@ -23,4 +23,9 @@
         
    -
    \ No newline at end of file
    +      
    +    
    +
    
    From 862088e4b85a0621f184f6ecea71367d05f9ba72 Mon Sep 17 00:00:00 2001
    From: Absinthe 
    Date: Sat, 11 Dec 2021 11:59:28 +0800
    Subject: [PATCH 54/61] Explicitly specify `android:exported` to make
     compatible with Android 12.
    
    ---
     lib/utilcode/src/main/AndroidManifest.xml | 2 ++
     1 file changed, 2 insertions(+)
    
    diff --git a/lib/utilcode/src/main/AndroidManifest.xml b/lib/utilcode/src/main/AndroidManifest.xml
    index fc5b75e0e3..d45dd57787 100644
    --- a/lib/utilcode/src/main/AndroidManifest.xml
    +++ b/lib/utilcode/src/main/AndroidManifest.xml
    @@ -5,12 +5,14 @@
     
             
     
             
    Date: Mon, 18 Jul 2022 17:02:24 +0800
    Subject: [PATCH 55/61] =?UTF-8?q?[M]=20=E4=BF=AE=E6=94=B9BarUtils=E6=96=B9?=
     =?UTF-8?q?=E6=B3=95=E5=88=97=E8=A1=A8=E5=8F=8A=E6=8F=8F=E8=BF=B0?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     lib/utilcode/README-CN.md | 1 +
     lib/utilcode/README.md    | 1 +
     2 files changed, 2 insertions(+)
    
    diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
    index 260cabac24..a6ab4b3d09 100644
    --- a/lib/utilcode/README-CN.md
    +++ b/lib/utilcode/README-CN.md
    @@ -141,6 +141,7 @@ getNavBarColor                       : 获取导航栏颜色
     isSupportNavBar                      : 判断是否支持导航栏
     setNavBarLightMode                   : 设置导航栏是否为浅色模式
     isNavBarLightMode                    : 判断导航栏是否为浅色模式
    +transparentNavBar                    : 透明导航栏
     ```
     
     * ### 亮度相关 -> [BrightnessUtils.java][brightness.java] -> [Demo][brightness.demo]
    diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md
    index cdabfba45a..9d2025ebb0 100644
    --- a/lib/utilcode/README.md
    +++ b/lib/utilcode/README.md
    @@ -140,6 +140,7 @@ getNavBarColor
     isSupportNavBar
     setNavBarLightMode
     isNavBarLightMode
    +transparentNavBar
     ```
     
     * ### About Brightness -> [BrightnessUtils.java][brightness.java] -> [Demo][brightness.demo]
    
    From 62bf1646bf43427de4f30ff0653a3dfe6da90634 Mon Sep 17 00:00:00 2001
    From: taochen <935612713@qq.com>
    Date: Tue, 19 Jul 2022 12:00:46 +0800
    Subject: [PATCH 56/61] =?UTF-8?q?[F]=20TargetSdkVersion=2030=20AppUtils.is?=
     =?UTF-8?q?AppInstalled=E8=BF=94=E5=9B=9E=E9=94=99=E8=AF=AF?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     lib/utilcode/src/main/AndroidManifest.xml | 9 +++++++++
     1 file changed, 9 insertions(+)
    
    diff --git a/lib/utilcode/src/main/AndroidManifest.xml b/lib/utilcode/src/main/AndroidManifest.xml
    index d45dd57787..ab497595d4 100644
    --- a/lib/utilcode/src/main/AndroidManifest.xml
    +++ b/lib/utilcode/src/main/AndroidManifest.xml
    @@ -1,6 +1,15 @@
     
     
    +    
    +        
    +            
    +        
    +        
    +            
    +        
    +    
    +
         
     
             
    Date: Tue, 19 Jul 2022 17:31:46 +0800
    Subject: [PATCH 57/61] =?UTF-8?q?[M]=20AppUtils=E5=A2=9E=E5=8A=A0getAppMin?=
     =?UTF-8?q?SdkVersion,=20getAppTargetSdkVersion=E6=94=AF=E6=8C=81?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     .../utilcode/pkg/feature/app/AppActivity.kt   | 108 ++++++++--------
     lib/utilcode/README-CN.md                     |   2 +
     lib/utilcode/README.md                        |   2 +
     .../com/blankj/utilcode/util/AppUtils.java    | 115 ++++++++++++++++--
     .../debug/tool/appInfo/AppInfoItem.java       |  15 ++-
     5 files changed, 173 insertions(+), 69 deletions(-)
    
    diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
    index 175fa1bc3b..21eb351146 100644
    --- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
    +++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
    @@ -54,7 +54,10 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
     
         override fun bindItems(): MutableList> {
             return CollectionUtils.newArrayList(
    -                CommonItemSwitch("registerAppStatusChangedListener", { isRegisterAppStatusChangedListener }, {
    +            CommonItemSwitch(
    +                "registerAppStatusChangedListener",
    +                { isRegisterAppStatusChangedListener },
    +                {
                         isRegisterAppStatusChangedListener = it
                         if (it) {
                             AppUtils.registerAppStatusChangedListener(this)
    @@ -62,55 +65,63 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
                             AppUtils.unregisterAppStatusChangedListener(this)
                         }
                     }),
    -                CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()),
    -                CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()),
    -                CommonItemTitle("isAppSystem", AppUtils.isAppSystem().toString()),
    -                CommonItemTitle("isAppForeground", AppUtils.isAppForeground(AppUtils.getAppPackageName()).toString()),
    -                CommonItemTitle("isAppRunning", AppUtils.isAppRunning(AppUtils.getAppPackageName()).toString()),
    -                CommonItemImage("getAppIcon") {
    -                    it.setImageDrawable(AppUtils.getAppIcon())
    -                },
    -                CommonItemTitle("getAppPackageName", AppUtils.getAppPackageName()),
    -                CommonItemTitle("getAppName", AppUtils.getAppName()),
    -                CommonItemTitle("getAppPath", AppUtils.getAppPath()),
    -                CommonItemTitle("getAppVersionName", AppUtils.getAppVersionName()),
    -                CommonItemTitle("getAppVersionCode", AppUtils.getAppVersionCode().toString()),
    -                CommonItemTitle("getAppSignaturesSHA1", AppUtils.getAppSignaturesSHA1().toString()),
    -                CommonItemTitle("getAppSignaturesSHA256", AppUtils.getAppSignaturesSHA256().toString()),
    -                CommonItemTitle("getAppSignaturesMD5", AppUtils.getAppSignaturesMD5().toString()),
    -                CommonItemTitle("getAppUid", AppUtils.getAppUid().toString()),
    -                CommonItemTitle("getApkInfo", AppUtils.getApkInfo(AppUtils.getAppPath()).toString()),
    -
    -                CommonItemClick(R.string.app_install) {
    -                    if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
    -                        ToastUtils.showShort(R.string.app_install_tips)
    +            CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()),
    +            CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()),
    +            CommonItemTitle("isAppSystem", AppUtils.isAppSystem().toString()),
    +            CommonItemTitle(
    +                "isAppForeground",
    +                AppUtils.isAppForeground(AppUtils.getAppPackageName()).toString()
    +            ),
    +            CommonItemTitle(
    +                "isAppRunning",
    +                AppUtils.isAppRunning(AppUtils.getAppPackageName()).toString()
    +            ),
    +            CommonItemImage("getAppIcon") {
    +                it.setImageDrawable(AppUtils.getAppIcon())
    +            },
    +            CommonItemTitle("getAppPackageName", AppUtils.getAppPackageName()),
    +            CommonItemTitle("getAppName", AppUtils.getAppName()),
    +            CommonItemTitle("getAppPath", AppUtils.getAppPath()),
    +            CommonItemTitle("getAppVersionName", AppUtils.getAppVersionName()),
    +            CommonItemTitle("getAppVersionCode", AppUtils.getAppVersionCode().toString()),
    +            CommonItemTitle("getAppMinSdkVersion", AppUtils.getAppMinSdkVersion().toString()),
    +            CommonItemTitle("getAppTargetSdkVersion", AppUtils.getAppTargetSdkVersion().toString()),
    +            CommonItemTitle("getAppSignaturesSHA1", AppUtils.getAppSignaturesSHA1().toString()),
    +            CommonItemTitle("getAppSignaturesSHA256", AppUtils.getAppSignaturesSHA256().toString()),
    +            CommonItemTitle("getAppSignaturesMD5", AppUtils.getAppSignaturesMD5().toString()),
    +            CommonItemTitle("getAppUid", AppUtils.getAppUid().toString()),
    +            CommonItemTitle("getApkInfo", AppUtils.getApkInfo(AppUtils.getAppPath()).toString()),
    +
    +            CommonItemClick(R.string.app_install) {
    +                if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
    +                    ToastUtils.showShort(R.string.app_install_tips)
    +                } else {
    +                    if (!FileUtils.isFileExists(Config.TEST_APK_PATH)) {
    +                        ReleaseInstallApkTask(listener).execute()
                         } else {
    -                        if (!FileUtils.isFileExists(Config.TEST_APK_PATH)) {
    -                            ReleaseInstallApkTask(listener).execute()
    -                        } else {
    -                            listener.onReleased()
    -                        }
    +                        listener.onReleased()
                         }
    -                },
    -                CommonItemClick(R.string.app_uninstall) {
    -                    if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
    -                        AppUtils.uninstallApp(Config.TEST_PKG)
    -                    } else {
    -                        ToastUtils.showShort(R.string.app_uninstall_tips)
    -                    }
    -                },
    -                CommonItemClick(R.string.app_launch) {
    -                    AppUtils.launchApp(this.packageName)
    -                },
    -                CommonItemClick(R.string.app_relaunch) {
    -                    AppUtils.relaunchApp()
    -                },
    -                CommonItemClick(R.string.app_launch_details_settings, true) {
    -                    AppUtils.launchAppDetailsSettings()
    -                },
    -                CommonItemClick(R.string.app_exit) {
    -                    AppUtils.exitApp()
                     }
    +            },
    +            CommonItemClick(R.string.app_uninstall) {
    +                if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
    +                    AppUtils.uninstallApp(Config.TEST_PKG)
    +                } else {
    +                    ToastUtils.showShort(R.string.app_uninstall_tips)
    +                }
    +            },
    +            CommonItemClick(R.string.app_launch) {
    +                AppUtils.launchApp(this.packageName)
    +            },
    +            CommonItemClick(R.string.app_relaunch) {
    +                AppUtils.relaunchApp()
    +            },
    +            CommonItemClick(R.string.app_launch_details_settings, true) {
    +                AppUtils.launchAppDetailsSettings()
    +            },
    +            CommonItemClick(R.string.app_exit) {
    +                AppUtils.exitApp()
    +            }
             )
         }
     
    @@ -130,7 +141,8 @@ class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
         }
     }
     
    -class ReleaseInstallApkTask(private val mListener: OnReleasedListener) : ThreadUtils.SimpleTask() {
    +class ReleaseInstallApkTask(private val mListener: OnReleasedListener) :
    +    ThreadUtils.SimpleTask() {
     
         override fun doInBackground() {
             ResourceUtils.copyFileFromAssets("test_install", Config.TEST_APK_PATH)
    diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
    index a6ab4b3d09..d8b9591fe7 100644
    --- a/lib/utilcode/README-CN.md
    +++ b/lib/utilcode/README-CN.md
    @@ -72,6 +72,8 @@ getAppName                        : 获取 App 名称
     getAppPath                        : 获取 App 路径
     getAppVersionName                 : 获取 App 版本号
     getAppVersionCode                 : 获取 App 版本码
    +getAppMinSdkVersion               : 获取 App 支持最低系统版本号
    +getAppTargetSdkVersion            : 获取 App 目标系统版本号
     getAppSignatures                  : 获取 App 签名
     getAppSignaturesSHA1              : 获取应用签名的的 SHA1 值
     getAppSignaturesSHA256            : 获取应用签名的的 SHA256 值
    diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md
    index 9d2025ebb0..b88bcbcfbd 100644
    --- a/lib/utilcode/README.md
    +++ b/lib/utilcode/README.md
    @@ -72,6 +72,8 @@ getAppName
     getAppPath
     getAppVersionName
     getAppVersionCode
    +getAppMinSdkVersion
    +getAppTargetSdkVersion
     getAppSignatures
     getAppSignaturesSHA1
     getAppSignaturesSHA256
    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 8f03e1cf1f..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
    @@ -14,13 +14,13 @@
     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;
     
    -import androidx.annotation.NonNull;
    -import androidx.annotation.Nullable;
    -
     /**
      * 
      *     author: Blankj
    @@ -541,6 +541,65 @@ 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.
          *
    @@ -721,6 +780,8 @@ private static List getAppSignaturesHash(final String packageName, final
          * 
  • path of package
  • *
  • version name
  • *
  • version code
  • + *
  • minimum sdk version code
  • + *
  • target sdk version code
  • *
  • is system
  • * * @@ -740,6 +801,8 @@ public static AppInfo getAppInfo() { *
  • path of package
  • *
  • version name
  • *
  • version code
  • + *
  • minimum sdk version code
  • + *
  • target sdk version code
  • *
  • is system
  • * * @@ -829,13 +892,18 @@ private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) { String packageName = pi.packageName; ApplicationInfo ai = pi.applicationInfo; if (ai == null) { - return new AppInfo(packageName, "", null, "", versionName, versionCode, false); + 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; + 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); } /** @@ -843,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; @@ -907,14 +977,31 @@ 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); } @@ -928,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/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java b/lib/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java index 76351e4b10..54895ee71f 100644 --- a/lib/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java +++ b/lib/utildebug/src/main/java/com/blankj/utildebug/debug/tool/appInfo/AppInfoItem.java @@ -5,10 +5,12 @@ import android.view.View.OnClickListener; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; + import com.blankj.utilcode.util.AppUtils; import com.blankj.utilcode.util.ClickUtils; import com.blankj.utilcode.util.StringUtils; -import com.blankj.utildebug.DebugUtils; import com.blankj.utildebug.R; import com.blankj.utildebug.base.rv.BaseItem; import com.blankj.utildebug.base.rv.ItemViewHolder; @@ -16,9 +18,6 @@ import java.util.ArrayList; import java.util.List; -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - /** *
      *     author: blankj
    @@ -29,8 +28,8 @@
      */
     public class AppInfoItem extends BaseItem {
     
    -    private String          mTitle;
    -    private String          mContent;
    +    private String mTitle;
    +    private String mContent;
         private OnClickListener mListener;
     
         private TextView titleTv;
    @@ -71,9 +70,9 @@ public static List getAppInfoItems() {
             appInfoItems.add(new AppInfoItem(R.string.du_app_info_version_name, AppUtils.getAppVersionName()));
             appInfoItems.add(new AppInfoItem(R.string.du_app_info_version_code, String.valueOf(AppUtils.getAppVersionCode())));
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    -            appInfoItems.add(new AppInfoItem(R.string.du_app_info_min_sdk_version, String.valueOf(DebugUtils.getApp().getApplicationInfo().minSdkVersion)));
    +            appInfoItems.add(new AppInfoItem(R.string.du_app_info_min_sdk_version, String.valueOf(AppUtils.getAppMinSdkVersion())));
             }
    -        appInfoItems.add(new AppInfoItem(R.string.du_app_info_target_sdk_version, String.valueOf(DebugUtils.getApp().getApplicationInfo().targetSdkVersion)));
    +        appInfoItems.add(new AppInfoItem(R.string.du_app_info_target_sdk_version, String.valueOf(AppUtils.getAppTargetSdkVersion())));
             appInfoItems.add(new AppInfoItem(R.string.du_app_info_open_app_info_page, "", new OnClickListener() {
                 @Override
                 public void onClick(View v) {
    
    From 5f739314d9eadeb5cad7f0e6876d2606480fc1f5 Mon Sep 17 00:00:00 2001
    From: Blankj 
    Date: Sat, 15 Oct 2022 00:45:11 +0800
    Subject: [PATCH 58/61] fix: some bugs
    
    ---
     CHANGELOG.md                                  |  1 +
     buildSrc/src/main/groovy/Config.groovy        |  6 +--
     lib/utilcode/README-CN.md                     | 11 +++--
     lib/utilcode/README.md                        |  3 +-
     .../blankj/utilcode/util/ActivityUtils.java   |  9 ++--
     .../com/blankj/utilcode/util/BarUtils.java    |  4 +-
     .../com/blankj/utilcode/util/DeviceUtils.java | 46 +++++++++++++++++--
     module_config.json                            |  2 +-
     8 files changed, 63 insertions(+), 19 deletions(-)
    
    diff --git a/CHANGELOG.md b/CHANGELOG.md
    index c4bcc19c85..73e8145bf1 100644
    --- a/CHANGELOG.md
    +++ b/CHANGELOG.md
    @@ -1,3 +1,4 @@
    +* `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.
    diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
    index 268ec666ce..9a8d69d659 100644
    --- a/buildSrc/src/main/groovy/Config.groovy
    +++ b/buildSrc/src/main/groovy/Config.groovy
    @@ -6,8 +6,8 @@ class Config {
         static compileSdkVersion = 29
         static minSdkVersion = 14
         static targetSdkVersion = 29
    -    static versionCode = 1_030_007
    -    static versionName = '1.31.0'// 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 = '4.1.0'
    @@ -34,7 +34,7 @@ class Config {
                 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: false, localPath: "./lib/utilcode", remotePath: "com.blankj:utilcodex:$Config.versionName"),
    +            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*/
    diff --git a/lib/utilcode/README-CN.md b/lib/utilcode/README-CN.md
    index d8b9591fe7..6610b3be99 100644
    --- a/lib/utilcode/README-CN.md
    +++ b/lib/utilcode/README-CN.md
    @@ -3,7 +3,7 @@
     Gradle:
     ```groovy
     // if u use AndroidX, use the following
    -implementation 'com.blankj:utilcodex:1.31.0'
    +implementation 'com.blankj:utilcodex:1.31.1'
     
     // Not in maintenance
     implementation 'com.blankj:utilcode:1.30.7'
    @@ -1210,10 +1210,11 @@ removeListener: 移除消息监听器
     
     * ### URI 相关 -> [UriUtils.java][uri.java]
     ```
    -res2Uri  : res 转 uri
    -file2Uri : file 转 uri
    -uri2File : uri 转 file
    -uri2Bytes: uri 转 bytes
    +res2Uri            : res 转 uri
    +file2Uri           : file 转 uri
    +uri2File           : uri 转 file
    +uri2FileNoCacheCopy: uri 转 file 不拷贝缓存
    +uri2Bytes          : uri 转 bytes
     ```
     
     * ### UtilsTransActivity -> [UtilsTransActivity.java][trans.java]
    diff --git a/lib/utilcode/README.md b/lib/utilcode/README.md
    index b88bcbcfbd..570f58fc46 100644
    --- a/lib/utilcode/README.md
    +++ b/lib/utilcode/README.md
    @@ -3,7 +3,7 @@
     Gradle:
     ```groovy
     // if u use AndroidX, use the following
    -implementation 'com.blankj:utilcodex:1.31.0'
    +implementation 'com.blankj:utilcodex:1.31.1'
     
     // Not in maintenance
     implementation 'com.blankj:utilcode:1.30.6'
    @@ -1212,6 +1212,7 @@ removeListener
     res2Uri
     file2Uri
     uri2File
    +uri2FileNoCacheCopy
     uri2Bytes
     ```
     
    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 10858f75f4..056668652c 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
    @@ -2013,10 +2013,11 @@ private static boolean startActivity(final Intent intent,
         }
     
         private static boolean isIntentAvailable(final Intent intent) {
    -        return Utils.getApp()
    -                .getPackageManager()
    -                .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
    -                .size() > 0;
    +//        return Utils.getApp()
    +//                .getPackageManager()
    +//                .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
    +//                .size() > 0;
    +        return true;
         }
     
         private static boolean startActivityForResult(final Activity activity,
    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 ece4f7faba..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
    @@ -57,7 +57,7 @@ private BarUtils() {
          * @return the status bar's height
          */
         public static int getStatusBarHeight() {
    -        Resources resources = Utils.getApp().getResources();
    +        Resources resources = Resources.getSystem();
             int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
             return resources.getDimensionPixelSize(resourceId);
         }
    @@ -483,7 +483,7 @@ private static void invokePanels(final String methodName) {
          * @return the navigation bar's height
          */
         public static int getNavBarHeight() {
    -        Resources res = Utils.getApp().getResources();
    +        Resources res = Resources.getSystem();
             int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
             if (resourceId != 0) {
                 return res.getDimensionPixelSize(resourceId);
    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 e6feb5fdaa..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
    @@ -13,16 +13,19 @@
     import android.telephony.TelephonyManager;
     import android.text.TextUtils;
     
    -import androidx.annotation.RequiresApi;
    -import androidx.annotation.RequiresPermission;
    -
    +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;
    @@ -382,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;
    @@ -389,6 +393,42 @@ 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. * diff --git a/module_config.json b/module_config.json index 18f416382a..87233122b9 100644 --- a/module_config.json +++ b/module_config.json @@ -23,7 +23,7 @@ {"name": "lib_base", "isApply": true, "useLocal": true, "localPath": "./lib/base"}, {"name": "lib_common", "isApply": true, "useLocal": true, "localPath": "./lib/common"}, {"name": "lib_subutil", "isApply": true, "useLocal": true, "localPath": "./lib/subutil"}, - {"name": "lib_utilcode", "isApply": true, "useLocal": false, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"}, + {"name": "lib_utilcode", "isApply": true, "useLocal": true, "localPath": "./lib/utilcode", "remotePath": "com.blankj:utilcodex:$Config.versionName"}, {"name": "lib_utildebug", "isApply": true, "useLocal": true, "localPath": "./lib/utildebug"}, {"name": "lib_utildebug_no_op", "isApply": true, "useLocal": true, "localPath": "./lib/utildebug-no-op"} ] From 99be3102e1b5dce8bf051721008811eed3dae0a0 Mon Sep 17 00:00:00 2001 From: taochen <935612713@qq.com> Date: Fri, 21 Oct 2022 15:42:20 +0800 Subject: [PATCH 59/61] =?UTF-8?q?[F]=20=E9=83=A8=E5=88=86=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=B8=82=E5=9C=BA=E4=BB=A5=E6=89=80=E8=B0=93ActivityU?= =?UTF-8?q?tils=E9=9A=90=E7=A7=81=E5=90=88=E8=A7=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E6=8B=92=E7=BB=9D=E5=BA=94=E7=94=A8=E4=B8=8A=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blankj/utilcode/util/ActivityUtils.java | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) 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 056668652c..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 @@ -1997,29 +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; - return true; - } - private static boolean startActivityForResult(final Activity activity, final Bundle extras, final String pkg, @@ -2036,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; } @@ -2079,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; } From 19349b9998224f04385c37f643fc96e69faf33bd Mon Sep 17 00:00:00 2001 From: simple <383559698@qq.com> Date: Wed, 24 Apr 2024 19:22:35 +0800 Subject: [PATCH 60/61] update VibrateUtils --- buildSrc/src/main/groovy/Config.groovy | 2 +- .../pkg/feature/vibrate/VibrateActivity.kt | 22 +++++- .../pkg/src/main/res/values/strings.xml | 1 + .../blankj/utilcode/util/VibrateUtils.java | 79 +++++++++++++++++++ 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy index a69b8907c7..9a8d69d659 100644 --- a/buildSrc/src/main/groovy/Config.groovy +++ b/buildSrc/src/main/groovy/Config.groovy @@ -34,7 +34,7 @@ class Config { 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: false, localPath: "./lib/utilcode", remotePath: "com.blankj:utilcodex:$Config.versionName"), + 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*/ 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..ee88dab0fa 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,22 @@ 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.vibrateCompat(longArrayOf(0, 1000, 1000, 2000, 2000, 1000), 1) +// VibrateUtils.vibrateCompat(1000) + }, 1000) + }, + CommonItemClick(R.string.vibrate_cancel) { + VibrateUtils.cancel() + } ) } @@ -44,4 +55,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/res/values/strings.xml b/feature/utilcode/pkg/src/main/res/values/strings.xml index ccec698647..551f9adbaf 100644 --- a/feature/utilcode/pkg/src/main/res/values/strings.xml +++ b/feature/utilcode/pkg/src/main/res/values/strings.xml @@ -366,5 +366,6 @@ Vibrate 1000ms Vibrate Custom + Vibrate Background Cancel diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java index 622d657817..8d2ab055e4 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java @@ -1,7 +1,11 @@ package com.blankj.utilcode.util; import android.content.Context; +import android.media.AudioAttributes; +import android.os.Build; import android.os.Vibrator; + +import androidx.annotation.RequiresApi; import androidx.annotation.RequiresPermission; import static android.Manifest.permission.VIBRATE; @@ -35,6 +39,39 @@ public static void vibrate(final long milliseconds) { vibrator.vibrate(milliseconds); } + /** + * Vibrate. + *

    Must hold {@code }

    + * + * @param milliseconds The number of milliseconds to vibrate. + * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, + * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or + * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for + * vibrations associated with incoming calls. + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @RequiresPermission(VIBRATE) + public static void vibrate(final long milliseconds, AudioAttributes attributes) { + Vibrator vibrator = getVibrator(); + if (vibrator == null) return; + vibrator.vibrate(milliseconds, attributes); + } + + /** + * VibrateCompat + *

    Must hold {@code }

    + * + * @param milliseconds he number of milliseconds to vibrate. + */ + @RequiresPermission(VIBRATE) + public static void vibrateCompat(final long milliseconds) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + vibrate(milliseconds, getAudioAttributes()); + } else { + vibrate(milliseconds); + } + } + /** * Vibrate. *

    Must hold {@code }

    @@ -49,6 +86,41 @@ public static void vibrate(final long[] pattern, final int repeat) { vibrator.vibrate(pattern, repeat); } + /** + * Vibrate. + *

    Must hold {@code }

    + * + * @param pattern An array of longs of times for which to turn the vibrator on or off. + * @param repeat The index into pattern at which to repeat, or -1 if you don't want to repeat. + * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, + * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or + * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for + * vibrations associated with incoming calls. + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @RequiresPermission(VIBRATE) + public static void vibrate(final long[] pattern, final int repeat, AudioAttributes attributes) { + Vibrator vibrator = getVibrator(); + if (vibrator == null) return; + vibrator.vibrate(pattern, repeat, attributes); + } + + /** + * VibrateCompat + *

    Must hold {@code }

    + * + * @param pattern An array of longs of times for which to turn the vibrator on or off. + * @param repeat The index into pattern at which to repeat, or -1 if you don't want to repeat. + */ + @RequiresPermission(VIBRATE) + public static void vibrateCompat(final long[] pattern, final int repeat) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + vibrate(pattern, repeat, getAudioAttributes()); + } else { + vibrate(pattern, repeat); + } + } + /** * Cancel vibrate. *

    Must hold {@code }

    @@ -66,4 +138,11 @@ private static Vibrator getVibrator() { } return vibrator; } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static AudioAttributes getAudioAttributes() { + return new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .build(); + } } From c7ebceb6675670080389472445d0bcb3c71f8bc9 Mon Sep 17 00:00:00 2001 From: simple <383559698@qq.com> Date: Thu, 25 Apr 2024 10:36:38 +0800 Subject: [PATCH 61/61] add VibrateUtils comment --- .../blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt | 1 + .../src/main/java/com/blankj/utilcode/util/VibrateUtils.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) 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 ee88dab0fa..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 @@ -41,6 +41,7 @@ class VibrateActivity : CommonActivity() { 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) diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java index 8d2ab055e4..164810381a 100644 --- a/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java +++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/VibrateUtils.java @@ -58,7 +58,7 @@ public static void vibrate(final long milliseconds, AudioAttributes attributes) } /** - * VibrateCompat + * VibrateCompat - Can vibrate in background *

    Must hold {@code }

    * * @param milliseconds he number of milliseconds to vibrate. @@ -106,7 +106,7 @@ public static void vibrate(final long[] pattern, final int repeat, AudioAttribut } /** - * VibrateCompat + * VibrateCompat - Can vibrate in background *

    Must hold {@code }

    * * @param pattern An array of longs of times for which to turn the vibrator on or off.