├── .gitignore ├── README.md ├── any_common ├── .gitignore ├── README.md ├── README_Utils.md ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dds │ │ └── common │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── dds │ │ └── common │ │ ├── Dialogs.java │ │ ├── Toasts.java │ │ ├── activity │ │ └── ActivityUtils2.java │ │ ├── app │ │ ├── ApkUtil.java │ │ └── AppUtils.java │ │ ├── file │ │ ├── FileDirUtil.java │ │ ├── FileUtils.java │ │ └── ZipUtils.java │ │ ├── hack │ │ ├── Hack.java │ │ ├── Supplier.java │ │ └── Suppliers.java │ │ ├── helper │ │ ├── ActivityLifecycleCallbacks.java │ │ ├── DeviceHelper.java │ │ ├── DisplayHelper.java │ │ ├── DrawableHelper.java │ │ ├── KeyboardHelper.java │ │ ├── StatusBarHelper.java │ │ ├── ViewDirection.java │ │ └── ViewHelper.java │ │ ├── io │ │ └── CloseUtils.java │ │ ├── lifecycle │ │ ├── ActivityUtils.java │ │ ├── ProcessUtils.java │ │ ├── Utils.java │ │ ├── UtilsActivityLifecycleImpl.java │ │ └── UtilsBridge.java │ │ ├── log │ │ ├── LogDelegate.java │ │ └── LogUtils.java │ │ ├── net │ │ ├── Apn.java │ │ └── NetworkUtils.java │ │ ├── permission │ │ └── Permissions.java │ │ ├── snack │ │ ├── SnackBars.java │ │ ├── SnackbarUtils.java │ │ └── WebContent.java │ │ ├── state │ │ ├── IState.java │ │ ├── State.java │ │ └── StateMachine.java │ │ └── utils │ │ ├── ArrayUtils.java │ │ ├── BarUtils.java │ │ ├── BrightnessUtils.java │ │ ├── BusUtils.java │ │ ├── CleanUtils.java │ │ ├── ClipboardUtils.java │ │ ├── CloneUtils.java │ │ ├── CollectionUtils.java │ │ ├── ConstUtils.java │ │ ├── ConvertUtils.java │ │ ├── CrashUtils.java │ │ ├── EncodeUtils.java │ │ ├── EncryptUtils.java │ │ ├── FlashlightUtils.java │ │ ├── FragmentUtils.java │ │ ├── GsonUtils.java │ │ ├── ImageUtils.java │ │ ├── JsonUtils.java │ │ ├── KeyboardUtils.java │ │ ├── LocationUtils.java │ │ ├── MapUtils.java │ │ ├── MetaDataUtils.java │ │ ├── NotificationUtils.java │ │ ├── ObjectUtils.java │ │ ├── PathUtils.java │ │ ├── PhoneUtils.java │ │ ├── ReflectUtils.java │ │ ├── RegexUtils.java │ │ ├── RomUtil.java │ │ ├── RomUtils.java │ │ ├── SDCardUtils.java │ │ ├── SPUtils.java │ │ ├── ScreenUtils.java │ │ ├── ShellUtils.java │ │ ├── SizeUtils.java │ │ ├── SpanUtils.java │ │ ├── SpannableStringUtils.java │ │ ├── StringUtils.java │ │ ├── ThreadUtils.java │ │ ├── ThrowableUtils.java │ │ ├── TimeUtils.java │ │ ├── TouchUtils.java │ │ ├── UriUtils.java │ │ ├── Versions.java │ │ ├── VibrateUtils.java │ │ ├── ViewUtils.java │ │ └── VolumeUtils.java │ └── test │ └── java │ └── com │ └── dds │ └── common │ ├── ExampleUnitTest.java │ └── hackTest.java ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ ├── app-release.apk │ └── output.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dds │ │ └── dddemo │ │ ├── ExampleInstrumentedTest.java │ │ └── hack │ │ └── HackTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── dds │ │ │ └── dddemo │ │ │ ├── App.java │ │ │ ├── MainActivity.java │ │ │ ├── hack │ │ │ ├── Bean.java │ │ │ └── HackDemo.java │ │ │ └── ui │ │ │ ├── DialogActivity.java │ │ │ ├── DrawHelperActivity.java │ │ │ ├── HackActivity.java │ │ │ ├── MediaPlayerActivity.java │ │ │ └── ToastActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_dialog.xml │ │ ├── activity_draw_helper.xml │ │ ├── activity_hack.xml │ │ ├── activity_main.xml │ │ ├── activity_media_player.xml │ │ └── activity_toast.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── network_permission_config.xml │ └── test │ └── java │ └── com │ └── dds │ └── dddemo │ └── ExampleUnitTest.java ├── art └── anytool2.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](art/anytool2.png) 2 | 3 | 本项目收录Android开发中的各种工具,旨在让你的开发更加简单快速 4 | 5 | This project includes various tools in Android development. make development faster and easier 6 | 7 | 8 | ## Instructions 9 | 10 | **关于项目** 11 | 12 | 我们常常在思考,我们也常常在感叹,新技术层出不穷,而我们的学习也变得越来越枯燥无味。学习的方法是总结,而能让我们进步的是分享和交流。 13 | 14 | We are often thinking, and we are often lamenting that new technologies are emerging one after another, and our learning has become more and more boring. The way to learn is to summarize, and what makes us progress is sharing and communication. 15 | 16 | 17 | ## details 18 | 19 | ### 1. any_common 20 | 21 | Here are some commonly used tools 22 | 23 | - File 24 | 25 | [FileDirUtil.java](any_common/src/main/java/com/dds/common/file/FileDirUtil.java) 26 | 27 | [FileUtils.java](any_common/src/main/java/com/dds/common/file/FileUtils.java) 28 | 29 | - dynamic permissions 30 | 31 | [Permissions.java](any_common/src/main/java/com/dds/common/permission/Permissions.java) 32 | 33 | - Log 34 | 35 | [LogA.java](any_common/src/main/java/com/dds/common/log/LogUtils.java) 36 | 37 | - Dialog 38 | 39 | [Toasts.java](any_common/src/main/java/com/dds/common/Toasts.java) 40 | 41 | [Dialogs.java](any_common/src/main/java/com/dds/common/Dialogs.java) 42 | 43 | [SnackBars.java](any_common/src/main/java/com/dds/common/snack/SnackBars.java) 44 | 45 | - net 46 | 47 | [NetworkUtils.java](any_common/src/main/java/com/dds/common/net/NetworkUtils.java) 48 | 49 | - state machines 50 | 51 | [StateMachine.java](any_common/src/main/java/com/dds/common/state/StateMachine.java) 52 | 53 | - app 54 | 55 | [AppUtils.java](any_common/src/main/java/com/dds/common/app/AppUtils.java) 56 | 57 | [ApkUtils.java](any_common/src/main/java/com/dds/common/app/ApkUtil.java) 58 | 59 | - utils 60 | 61 | [utils](any_common/src/main/java/com/dds/common/utils) 62 | 63 | [ArrayUtils.java](any_common/src/main/java/com/dds/common/utils/ArrayUtils.java) 64 | 65 | [BarUtils.java](any_common/src/main/java/com/dds/common/utils/BarUtils.java) 66 | 67 | [BrightnessUtils.java](any_common/src/main/java/com/dds/common/utils/BrightnessUtils.java) 68 | 69 | [BusUtils.java](any_common/src/main/java/com/dds/common/utils/BusUtils.java) 70 | 71 | [CleanUtils.java](any_common/src/main/java/com/dds/common/utils/CleanUtils.java) 72 | 73 | [ClipboardUtils.java](any_common/src/main/java/com/dds/common/utils/ClipboardUtils.java) 74 | 75 | [CloneUtils.java](any_common/src/main/java/com/dds/common/utils/CloneUtils.java) 76 | 77 | [CollectionUtils.java](any_common/src/main/java/com/dds/common/utils/CollectionUtils.java) 78 | 79 | [ConstUtils.java](any_common/src/main/java/com/dds/common/utils/ConstUtils.java) 80 | 81 | [ConvertUtils.java](any_common/src/main/java/com/dds/common/utils/ConvertUtils.java) 82 | 83 | [CrashUtils.java](any_common/src/main/java/com/dds/common/utils/CrashUtils.java) 84 | 85 | [EncodeUtils.java](any_common/src/main/java/com/dds/common/utils/EncodeUtils.java) 86 | 87 | [EncryptUtils.java](any_common/src/main/java/com/dds/common/utils/EncryptUtils.java) 88 | 89 | [FlashlightUtils.java](any_common/src/main/java/com/dds/common/utils/FlashlightUtils.java) 90 | 91 | [FragmentUtils.java](any_common/src/main/java/com/dds/common/utils/FragmentUtils.java) 92 | 93 | [GsonUtils.java](any_common/src/main/java/com/dds/common/utils/GsonUtils.java) 94 | 95 | [ImageUtils.java](any_common/src/main/java/com/dds/common/utils/ImageUtils.java) 96 | 97 | [JsonUtils.java](any_common/src/main/java/com/dds/common/utils/JsonUtils.java) 98 | 99 | [KeyboardUtils.java](any_common/src/main/java/com/dds/common/utils/KeyboardUtils.java) 100 | 101 | [LocationUtils.java](any_common/src/main/java/com/dds/common/utils/LocationUtils.java) 102 | 103 | [MapUtils.java](any_common/src/main/java/com/dds/common/utils/MapUtils.java) 104 | 105 | [MetaDataUtils.java](any_common/src/main/java/com/dds/common/utils/MetaDataUtils.java) 106 | 107 | [NotificationUtils.java](any_common/src/main/java/com/dds/common/utils/NotificationUtils.java) 108 | 109 | [ObjectUtils.java](any_common/src/main/java/com/dds/common/utils/ObjectUtils.java) 110 | 111 | [PathUtils.java](any_common/src/main/java/com/dds/common/utils/PathUtils.java) 112 | 113 | [PhoneUtils.java](any_common/src/main/java/com/dds/common/utils/PhoneUtils.java) 114 | 115 | [RegexUtils.java](any_common/src/main/java/com/dds/common/utils/RegexUtils.java) 116 | 117 | [RomUtil.java](any_common/src/main/java/com/dds/common/utils/RomUtil.java) 118 | 119 | [RomUtils.java](any_common/src/main/java/com/dds/common/utils/RomUtils.java) 120 | 121 | [ScreenUtils.java](any_common/src/main/java/com/dds/common/utils/ScreenUtils.java) 122 | 123 | [SDCardUtils.java](any_common/src/main/java/com/dds/common/utils/SDCardUtils.java) 124 | 125 | [ShellUtils.java](any_common/src/main/java/com/dds/common/utils/ShellUtils.java) 126 | 127 | [SizeUtils.java](any_common/src/main/java/com/dds/common/utils/SizeUtils.java) 128 | 129 | [SpannableStringUtils.java](any_common/src/main/java/com/dds/common/utils/SpannableStringUtils.java) 130 | 131 | [SpanUtils.java](any_common/src/main/java/com/dds/common/utils/SpanUtils.java) 132 | 133 | [SPUtils.java](any_common/src/main/java/com/dds/common/utils/SPUtils.java) 134 | 135 | [StringUtils.java](any_common/src/main/java/com/dds/common/utils/StringUtils.java) 136 | 137 | [ThreadUtils.java](any_common/src/main/java/com/dds/common/utils/ThreadUtils.java) 138 | 139 | [ThrowableUtils.java](any_common/src/main/java/com/dds/common/utils/ThrowableUtils.java) 140 | 141 | [TimeUtils.java](any_common/src/main/java/com/dds/common/utils/TimeUtils.java) 142 | 143 | [TouchUtils.java](any_common/src/main/java/com/dds/common/utils/TouchUtils.java) 144 | 145 | [UriUtils.java](any_common/src/main/java/com/dds/common/utils/UriUtils.java) 146 | 147 | [VibrateUtils.java](any_common/src/main/java/com/dds/common/utils/VibrateUtils.java) 148 | 149 | [ViewUtils.java](any_common/src/main/java/com/dds/common/utils/ViewUtils.java) 150 | 151 | [VolumeUtils.java](any_common/src/main/java/com/dds/common/utils/VolumeUtils.java) 152 | 153 | 154 | 155 | 156 | ### 2. csdn article 157 | 158 | - [优雅的解决Android运行时权限问题](https://blog.csdn.net/u011077027/article/details/100694123) 159 | - [优雅的hook私有方法](https://blog.csdn.net/u011077027/article/details/102630313) 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /any_common/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /any_common/README.md: -------------------------------------------------------------------------------- 1 | 1. request permission 2 | 3 | ```java 4 | Permissions.request(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, 5 | Manifest.permission.CAMERA}, integer -> { 6 | if (integer == PackageManager.PERMISSION_GRANTED) { 7 | Toasts.showShort(MainActivity.this, "成功accept : " + integer); 8 | } else { 9 | Toasts.showShort(MainActivity.this, "失败accept : " + integer); 10 | } 11 | }); 12 | ``` 13 | 14 | 2. Dialog tool 15 | 16 | 3. Toast tool 17 | 18 | 4. hook tool 19 | 20 | ```java 21 | class HackDemo{ 22 | 23 | private int fuc() { 24 | return 7; 25 | } 26 | 27 | } 28 | 29 | // hook above 30 | 31 | Hack.HackedMethod0 foo 32 | = Hack 33 | .into(HackDemo.class) 34 | .method("fuc") 35 | .returning(int.class) 36 | .withoutParams(); 37 | 38 | foo.invoke().on(simple) 39 | ``` -------------------------------------------------------------------------------- /any_common/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 30 5 | 6 | 7 | defaultConfig { 8 | minSdkVersion 21 9 | targetSdkVersion 30 10 | 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | 13 | } 14 | compileOptions { 15 | sourceCompatibility JavaVersion.VERSION_1_8 16 | targetCompatibility JavaVersion.VERSION_1_8 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | implementation 'androidx.appcompat:appcompat:1.1.0' 30 | implementation 'androidx.browser:browser:1.0.0' 31 | 32 | 33 | // other 34 | // library - snack - WebContent 35 | implementation 'com.google.android.material:material:1.0.0' 36 | 37 | // glide 38 | implementation 'com.github.bumptech.glide:glide:4.9.0' 39 | annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' 40 | 41 | // okhttp3 42 | implementation 'com.squareup.okhttp3:okhttp:3.14.2' 43 | 44 | // gson 45 | implementation 'com.google.code.gson:gson:2.8.5' 46 | 47 | // test 48 | testImplementation 'junit:junit:4.12' 49 | androidTestImplementation 'androidx.test:runner:1.2.0' 50 | androidTestImplementation 'androidx.test.ext:junit:1.1.2-alpha02' 51 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 52 | } 53 | -------------------------------------------------------------------------------- /any_common/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | 24 | 25 | #---------------------------------okhttp3----------------------------------------------- 26 | # JSR 305 annotations are for embedding nullability information. 27 | -dontwarn javax.annotation.** 28 | # A resource is loaded with a relative path so the package of this class must be preserved. 29 | -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase 30 | # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. 31 | -dontwarn org.codehaus.mojo.animal_sniffer.* 32 | # OkHttp platform used only on JVM and when Conscrypt dependency is available. 33 | -dontwarn okhttp3.internal.platform.ConscryptPlatform -------------------------------------------------------------------------------- /any_common/src/androidTest/java/com/dds/common/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.dds.common; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | 9 | import com.dds.common.file.FileDirUtil; 10 | 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | public static final String TAG = "dds_test"; 20 | 21 | @Test 22 | public void useAppContext() { 23 | // Context of the app under test. 24 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 25 | 26 | assertEquals("com.trustmobi.myapplication", appContext.getPackageName()); 27 | } 28 | 29 | @Test 30 | public void testFileDirUtil() { 31 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 32 | 33 | String fileDir = FileDirUtil.getFileDir(appContext); 34 | Log.d(TAG, "getFileDir:" + fileDir); 35 | assertEquals(fileDir, "/data/user/0/com.utils.library.test/files"); 36 | 37 | String fileDirCustom = FileDirUtil.getFileDir(appContext, "test"); 38 | Log.d(TAG, "getFileDir:" + fileDirCustom); 39 | assertEquals(fileDirCustom, "/data/user/0/com.utils.library.test/files/test"); 40 | 41 | String cacheDir = FileDirUtil.getCacheDir(appContext); 42 | Log.d(TAG, "getCacheDir:" + cacheDir); 43 | 44 | String cacheDir1 = FileDirUtil.getCacheDir(appContext, "test"); 45 | Log.d(TAG, "getCacheDir:" + cacheDir1); 46 | 47 | String externalFileDir = FileDirUtil.getExternalFileDir(appContext); 48 | Log.d(TAG, "getExternalFileDir:" + externalFileDir); 49 | assertEquals(externalFileDir, "/storage/emulated/0/Android/data/com.utils.library.test/files"); 50 | 51 | String externalFileDir1 = FileDirUtil.getExternalFileDir(appContext, "test"); 52 | Log.d(TAG, "getExternalFileDir:" + externalFileDir1); 53 | 54 | 55 | String externalCacheDir = FileDirUtil.getExternalCacheDir(appContext); 56 | Log.d(TAG, "getExternalFileDir:" + externalCacheDir); 57 | 58 | String externalCacheDir1 = FileDirUtil.getExternalCacheDir(appContext, "test"); 59 | Log.d(TAG, "getExternalFileDir:" + externalCacheDir1); 60 | 61 | 62 | String publicDownloadDir = FileDirUtil.getPublicDownloadDir(); 63 | Log.d(TAG, "getPublicDownloadDir:" + publicDownloadDir); 64 | 65 | 66 | boolean is = FileDirUtil.isMountSdcard(); 67 | Log.d(TAG, "isMountSdcard:" + is); 68 | assertTrue(is); 69 | 70 | 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /any_common/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/Dialogs.java: -------------------------------------------------------------------------------- 1 | package com.dds.common; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.app.ProgressDialog; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | 9 | import androidx.annotation.CheckResult; 10 | import androidx.annotation.Nullable; 11 | import androidx.annotation.StringRes; 12 | 13 | /** 14 | * @author dds 15 | */ 16 | public class Dialogs { 17 | /** 18 | * Create an non-cancellable alert dialog builder. 19 | */ 20 | public static @CheckResult 21 | Builder buildAlert(final Activity activity, final @StringRes int title, final @StringRes int message) { 22 | return buildAlert(activity, title != 0 ? activity.getText(title) : null, message != 0 ? activity.getText(message) : null); 23 | } 24 | 25 | public static @CheckResult 26 | Builder buildAlert(final Activity activity, final @Nullable CharSequence title, final @Nullable CharSequence message) { 27 | final Builder builder = new Builder(activity); 28 | builder.setCancelable(true); 29 | if (title != null) builder.setTitle(title); 30 | if (message != null) builder.setMessage(message); 31 | return builder; 32 | } 33 | 34 | /** 35 | * Provide shortcuts for simpler building 36 | */ 37 | public static class Builder extends AlertDialog.Builder { 38 | 39 | public @CheckResult 40 | Builder withOkButton(final @Nullable Runnable task) { 41 | setPositiveButton(android.R.string.ok, task == null ? null : new DialogInterface.OnClickListener() { 42 | @Override 43 | public void onClick(DialogInterface d, int w) { 44 | task.run(); 45 | } 46 | }); 47 | return this; 48 | } 49 | 50 | public @CheckResult 51 | Builder withCancelButton() { 52 | setNegativeButton(android.R.string.cancel, null); 53 | return this; 54 | } 55 | 56 | Builder(final Context context) { 57 | super(context, android.R.style.Theme_Material_Light_Dialog_Alert); 58 | } 59 | } 60 | 61 | public static @CheckResult 62 | FluentProgressDialog buildProgress(final Activity activity, final CharSequence message) { 63 | final FluentProgressDialog dialog = new FluentProgressDialog(activity); 64 | dialog.setMessage(message); 65 | return dialog; 66 | } 67 | 68 | public static class FluentProgressDialog extends ProgressDialog { 69 | 70 | FluentProgressDialog(final Context context) { 71 | super(context, android.R.style.Theme_Material_Light_Dialog_Alert); 72 | } 73 | 74 | public FluentProgressDialog indeterminate() { 75 | setIndeterminate(true); 76 | return this; 77 | } 78 | 79 | public FluentProgressDialog nonCancelable() { 80 | setCancelable(false); 81 | return this; 82 | } 83 | 84 | public void start() { 85 | super.show(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/Toasts.java: -------------------------------------------------------------------------------- 1 | package com.dds.common; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.widget.Toast; 7 | 8 | import androidx.annotation.IntDef; 9 | import androidx.annotation.StringRes; 10 | 11 | import java.lang.annotation.Retention; 12 | import java.lang.annotation.RetentionPolicy; 13 | 14 | /** 15 | * Created by dds 16 | */ 17 | public class Toasts { 18 | 19 | @IntDef({Toast.LENGTH_SHORT, Toast.LENGTH_LONG}) 20 | @Retention(RetentionPolicy.SOURCE) 21 | public @interface Duration { 22 | } 23 | 24 | private final static Looper MAIN_LOOPER = Looper.getMainLooper(); 25 | 26 | public static void showLong(final Context context, final CharSequence text) { 27 | show(context, text, Toast.LENGTH_LONG); 28 | } 29 | 30 | public static void showShort(final Context context, final CharSequence text) { 31 | show(context, text, Toast.LENGTH_SHORT); 32 | } 33 | 34 | public static void showLong(final Context context, final @StringRes int text) { 35 | show(context, text, Toast.LENGTH_LONG); 36 | } 37 | 38 | public static void showShort(final Context context, final @StringRes int text) { 39 | show(context, text, Toast.LENGTH_SHORT); 40 | } 41 | 42 | public static void show(final Context context, final @StringRes int text, final @Duration int length) { 43 | show(context, context.getText(text), length); 44 | } 45 | 46 | public static void show(final Context context, final CharSequence text, final @Duration int length) { 47 | final Looper my_looper = Looper.myLooper(); 48 | if (my_looper == MAIN_LOOPER) Toast.makeText(context, text, length).show(); 49 | else new Handler(MAIN_LOOPER).post(new Runnable() { 50 | @Override 51 | public void run() { 52 | Toast.makeText(context, text, length).show(); 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/activity/ActivityUtils2.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.activity; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.content.pm.ResolveInfo; 8 | import android.os.Bundle; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | *
14 |  *     time  : 2016/9/23
15 |  *     desc  : Activity相关工具类
16 |  * 
17 | */ 18 | public class ActivityUtils2 { 19 | 20 | private ActivityUtils2() { 21 | throw new UnsupportedOperationException("u can't instantiate me..."); 22 | } 23 | 24 | /** 25 | * 判断是否存在Activity 26 | * 27 | * @param context 上下文 28 | * @param packageName 包名 29 | * @param className activity全路径类名 30 | * @return {@code true}: 是
{@code false}: 否 31 | */ 32 | public static boolean isActivityExists(Context context, String packageName, String className) { 33 | Intent intent = new Intent(); 34 | intent.setClassName(packageName, className); 35 | return !(context.getPackageManager().resolveActivity(intent, 0) == null || 36 | intent.resolveActivity(context.getPackageManager()) == null || 37 | context.getPackageManager().queryIntentActivities(intent, 0).size() == 0); 38 | } 39 | 40 | /** 41 | * 打开Activity 42 | * 43 | * @param context 上下文 44 | * @param packageName 包名 45 | * @param className 全类名 46 | */ 47 | public static void launchActivity(Context context, String packageName, String className) { 48 | launchActivity(context, packageName, className, null); 49 | } 50 | 51 | /** 52 | * 打开Activity 53 | * 54 | * @param context 上下文 55 | * @param packageName 包名 56 | * @param className 全类名 57 | * @param bundle bundle 58 | */ 59 | public static void launchActivity(Context context, String packageName, String className, Bundle bundle) { 60 | context.startActivity(getComponentIntent(packageName, className, bundle)); 61 | } 62 | 63 | /** 64 | * 获取launcher activity 名字 65 | * 66 | * @param context 上下文 67 | * @param packageName 包名 68 | * @return launcher activity 69 | */ 70 | public static String getLauncherActivity(Context context, String packageName) { 71 | Intent intent = new Intent(Intent.ACTION_MAIN, null); 72 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 73 | PackageManager pm = context.getPackageManager(); 74 | List infos = pm.queryIntentActivities(intent, 0); 75 | for (ResolveInfo info : infos) { 76 | if (info.activityInfo.packageName.equals(packageName)) { 77 | return info.activityInfo.name; 78 | } 79 | } 80 | return "no " + packageName; 81 | } 82 | 83 | private static Intent getComponentIntent(String packageName, String className, Bundle bundle) { 84 | Intent intent = new Intent(Intent.ACTION_VIEW); 85 | if (bundle != null) intent.putExtras(bundle); 86 | ComponentName cn = new ComponentName(packageName, className); 87 | intent.setComponent(cn); 88 | return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/file/FileDirUtil.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.file; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | import java.io.File; 7 | 8 | /** 9 | * Created by dds on 2019/9/9. 10 | * android_shuai@163.com 11 | */ 12 | public class FileDirUtil { 13 | 14 | private FileDirUtil() { 15 | } 16 | 17 | /** 18 | * 沙箱 默认文件存储路径 data/data/file 19 | */ 20 | public static String getFileDir(Context context) { 21 | return String.valueOf(context.getFilesDir()); 22 | } 23 | 24 | /** 25 | * 沙箱 程序系统文件目录绝对路径 data/data/file/customPath 26 | * 27 | * @param context context 28 | * @param customPath customPath 29 | * @return data/data/file/customPath 30 | */ 31 | public static String getFileDir(Context context, String customPath) { 32 | String path = context.getFilesDir() + formatPath(customPath); 33 | mkdir(path); 34 | return path; 35 | } 36 | 37 | /** 38 | * @return 程序系统缓存目录 39 | */ 40 | public static String getCacheDir(Context context) { 41 | return String.valueOf(context.getCacheDir()); 42 | } 43 | 44 | /** 45 | * 程序系统缓存目录 中自定义路径 46 | * 47 | * @param context 上下文 48 | * @param customPath 自定义路径 49 | * @return /data/app/pkg/cache 50 | */ 51 | public static String getCacheDir(Context context, String customPath) { 52 | String path = context.getCacheDir() + formatPath(customPath); 53 | mkdir(path); 54 | return path; 55 | } 56 | 57 | /** 58 | * @return 内存卡文件目录 59 | */ 60 | public static String getExternalFileDir(Context context) { 61 | return String.valueOf(context.getExternalFilesDir("")); 62 | } 63 | 64 | /** 65 | * @param context 上下文 66 | * @param customPath 自定义路径 67 | * @return 内存卡文件目录 68 | */ 69 | public static String getExternalFileDir(Context context, String customPath) { 70 | String path = context.getExternalFilesDir("") + formatPath(customPath); 71 | mkdir(path); 72 | return path; 73 | } 74 | 75 | /** 76 | * @return 内存卡缓存目录 77 | */ 78 | public static String getExternalCacheDir(Context context) { 79 | return String.valueOf(context.getExternalCacheDir()); 80 | } 81 | 82 | /** 83 | * @param context 上下文 84 | * @param customPath 自定义路径 85 | * @return 内存卡缓存目录 86 | */ 87 | public static String getExternalCacheDir(Context context, String customPath) { 88 | String path = context.getExternalCacheDir() + formatPath(customPath); 89 | mkdir(path); 90 | return path; 91 | } 92 | 93 | /** 94 | * @return 公共下载文件夹 95 | */ 96 | public static String getPublicDownloadDir() { 97 | return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 98 | } 99 | 100 | /** 101 | * 创建文件夹 102 | * 103 | * @param DirPath 文件夹路径 104 | */ 105 | public static boolean mkdir(String DirPath) { 106 | File file = new File(DirPath); 107 | if (file.exists() && file.isDirectory()) { 108 | return true; 109 | } else { 110 | return file.mkdirs(); 111 | } 112 | 113 | 114 | } 115 | 116 | /** 117 | * 格式化文件路径 118 | * 示例: 传入 "sloop" "/sloop" "sloop/" "/sloop/" 119 | * 返回 "/sloop" 120 | */ 121 | private static String formatPath(String path) { 122 | if (!path.startsWith("/")) 123 | path = "/" + path; 124 | while (path.endsWith("/")) 125 | path = new String(path.toCharArray(), 0, path.length() - 1); 126 | return path; 127 | } 128 | 129 | /** 130 | * @return 存储卡是否挂载(存在) 131 | */ 132 | public static boolean isMountSdcard() { 133 | String status = Environment.getExternalStorageState(); 134 | return status.equals(Environment.MEDIA_MOUNTED); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/hack/Supplier.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.hack; 2 | 3 | /** 4 | * Represents a supplier of results. 5 | * 6 | *

There is no requirement that a new or distinct result be returned each 7 | * time the supplier is invoked. 8 | * 9 | *

This is a functional interface 10 | * whose functional method is {@link #get()}. 11 | * 12 | * @param the type of results supplied by this supplier 13 | */ 14 | public interface Supplier { 15 | 16 | /** 17 | * Gets a result. 18 | * 19 | * @return a result 20 | */ 21 | T get(); 22 | } 23 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/helper/ActivityLifecycleCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.helper; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | 7 | /** 8 | * @author dds 9 | * @date 2016-11-07 10 | * 11 | * https://github.com/yshrsmz/KeyboardVisibilityEvent/blob/master/keyboardvisibilityevent/src/main/java/net/yslibrary/android/keyboardvisibilityevent/AutoActivityLifecycleCallback.java 12 | */ 13 | 14 | public abstract class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { 15 | 16 | private final Activity mTargetActivity; 17 | 18 | public ActivityLifecycleCallbacks(Activity targetActivity) { 19 | mTargetActivity = targetActivity; 20 | } 21 | 22 | @Override 23 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 24 | 25 | } 26 | 27 | @Override 28 | public void onActivityStarted(Activity activity) { 29 | 30 | } 31 | 32 | @Override 33 | public void onActivityResumed(Activity activity) { 34 | 35 | } 36 | 37 | @Override 38 | public void onActivityPaused(Activity activity) { 39 | 40 | } 41 | 42 | @Override 43 | public void onActivityStopped(Activity activity) { 44 | 45 | } 46 | 47 | @Override 48 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) { 49 | 50 | } 51 | 52 | @Override 53 | public void onActivityDestroyed(Activity activity) { 54 | if (activity == mTargetActivity) { 55 | mTargetActivity.getApplication().unregisterActivityLifecycleCallbacks(this); 56 | onTargetActivityDestroyed(); 57 | } 58 | } 59 | 60 | protected abstract void onTargetActivityDestroyed(); 61 | } 62 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/helper/KeyboardHelper.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.helper; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Rect; 6 | import android.os.Build; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.view.ViewTreeObserver; 10 | import android.view.inputmethod.InputMethodManager; 11 | import android.widget.EditText; 12 | 13 | /** 14 | * @author cginechen 15 | * @date 2016-11-07 16 | *

17 | * https://github.com/yshrsmz/KeyboardVisibilityEvent/blob/master/keyboardvisibilityevent/src/main/java/net/yslibrary/android/keyboardvisibilityevent/KeyboardVisibilityEvent.java 18 | */ 19 | 20 | public class KeyboardHelper { 21 | /** 22 | * 显示软键盘的延迟时间 23 | */ 24 | public static final int SHOW_KEYBOARD_DELAY_TIME = 200; 25 | private static final String TAG = "QMUIKeyboardHelper"; 26 | private final static int KEYBOARD_VISIBLE_THRESHOLD_DP = 100; 27 | 28 | 29 | public static void showKeyboard(final EditText editText, boolean delay) { 30 | showKeyboard(editText, delay ? SHOW_KEYBOARD_DELAY_TIME : 0); 31 | } 32 | 33 | 34 | /** 35 | * 针对给定的editText显示软键盘(editText会先获得焦点). 可以和{@link #hideKeyboard(View)} 36 | * 搭配使用,进行键盘的显示隐藏控制。 37 | */ 38 | 39 | public static void showKeyboard(final EditText editText, int delay) { 40 | if (null == editText) 41 | return; 42 | 43 | if (!editText.requestFocus()) { 44 | Log.w(TAG, "showSoftInput() can not get focus"); 45 | return; 46 | } 47 | if (delay > 0) { 48 | editText.postDelayed(new Runnable() { 49 | @Override 50 | public void run() { 51 | InputMethodManager imm = (InputMethodManager) editText.getContext().getApplicationContext() 52 | .getSystemService(Context.INPUT_METHOD_SERVICE); 53 | imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); 54 | } 55 | }, delay); 56 | } else { 57 | InputMethodManager imm = (InputMethodManager) editText.getContext().getApplicationContext() 58 | .getSystemService(Context.INPUT_METHOD_SERVICE); 59 | imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); 60 | } 61 | } 62 | 63 | /** 64 | * 隐藏软键盘 可以和{@link #showKeyboard(EditText, boolean)}搭配使用,进行键盘的显示隐藏控制。 65 | * 66 | * @param view 当前页面上任意一个可用的view 67 | */ 68 | public static boolean hideKeyboard(final View view) { 69 | if (null == view) 70 | return false; 71 | 72 | InputMethodManager inputManager = (InputMethodManager) view.getContext().getApplicationContext() 73 | .getSystemService(Context.INPUT_METHOD_SERVICE); 74 | // 即使当前焦点不在editText,也是可以隐藏的。 75 | return inputManager.hideSoftInputFromWindow(view.getWindowToken(), 76 | InputMethodManager.HIDE_NOT_ALWAYS); 77 | } 78 | 79 | /** 80 | * Set keyboard visibility change event listener. 81 | * 82 | * @param activity Activity 83 | * @param listener KeyboardVisibilityEventListener 84 | */ 85 | @SuppressWarnings("deprecation") 86 | public static void setVisibilityEventListener(final Activity activity, 87 | final KeyboardVisibilityEventListener listener) { 88 | 89 | if (activity == null) { 90 | throw new NullPointerException("Parameter:activity must not be null"); 91 | } 92 | 93 | if (listener == null) { 94 | throw new NullPointerException("Parameter:listener must not be null"); 95 | } 96 | 97 | final View activityRoot = ViewHelper.getActivityRoot(activity); 98 | 99 | final ViewTreeObserver.OnGlobalLayoutListener layoutListener = 100 | new ViewTreeObserver.OnGlobalLayoutListener() { 101 | 102 | private final Rect r = new Rect(); 103 | 104 | private final int visibleThreshold = Math.round( 105 | DisplayHelper.dp2px(activity, KEYBOARD_VISIBLE_THRESHOLD_DP)); 106 | 107 | private boolean wasOpened = false; 108 | 109 | @Override 110 | public void onGlobalLayout() { 111 | activityRoot.getWindowVisibleDisplayFrame(r); 112 | 113 | int heightDiff = activityRoot.getRootView().getHeight() - r.height(); 114 | 115 | boolean isOpen = heightDiff > visibleThreshold; 116 | 117 | if (isOpen == wasOpened) { 118 | // keyboard state has not changed 119 | return; 120 | } 121 | 122 | wasOpened = isOpen; 123 | 124 | listener.onVisibilityChanged(isOpen); 125 | } 126 | }; 127 | activityRoot.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener); 128 | activity.getApplication() 129 | .registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(activity) { 130 | @Override 131 | protected void onTargetActivityDestroyed() { 132 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 133 | activityRoot.getViewTreeObserver() 134 | .removeOnGlobalLayoutListener(layoutListener); 135 | } else { 136 | activityRoot.getViewTreeObserver() 137 | .removeGlobalOnLayoutListener(layoutListener); 138 | } 139 | } 140 | }); 141 | } 142 | 143 | /** 144 | * Determine if keyboard is visible 145 | * 146 | * @param activity Activity 147 | * @return Whether keyboard is visible or not 148 | */ 149 | public static boolean isKeyboardVisible(Activity activity) { 150 | Rect r = new Rect(); 151 | 152 | View activityRoot = ViewHelper.getActivityRoot(activity); 153 | int visibleThreshold = 154 | Math.round(DisplayHelper.dp2px(activity, KEYBOARD_VISIBLE_THRESHOLD_DP)); 155 | 156 | activityRoot.getWindowVisibleDisplayFrame(r); 157 | 158 | int heightDiff = activityRoot.getRootView().getHeight() - r.height(); 159 | 160 | return heightDiff > visibleThreshold; 161 | } 162 | 163 | 164 | public interface KeyboardVisibilityEventListener { 165 | 166 | void onVisibilityChanged(boolean isOpen); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/helper/ViewDirection.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.helper; 2 | 3 | /** 4 | * 定义了从左到右,从上到下,从右到左,从下到上四个方向的类 5 | * Created by Kayo on 2017/2/7. 6 | */ 7 | 8 | public enum ViewDirection { 9 | LEFT_TO_RIGHT, 10 | TOP_TO_BOTTOM, 11 | RIGHT_TO_LEFT, 12 | BOTTOM_TO_TOP 13 | } 14 | 15 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/io/CloseUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.io; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | 6 | 7 | public class CloseUtils { 8 | 9 | private CloseUtils() { 10 | throw new UnsupportedOperationException("u can't instantiate me..."); 11 | } 12 | 13 | /** 14 | * 关闭IO 15 | * 16 | * @param closeables closeable 17 | */ 18 | public static void closeIO(Closeable... closeables) { 19 | if (closeables == null) return; 20 | for (Closeable closeable : closeables) { 21 | if (closeable != null) { 22 | try { 23 | closeable.close(); 24 | } catch (IOException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * 安静关闭IO 33 | * 34 | * @param closeables closeable 35 | */ 36 | public static void closeIOQuietly(Closeable... closeables) { 37 | if (closeables == null) return; 38 | for (Closeable closeable : closeables) { 39 | if (closeable != null) { 40 | try { 41 | closeable.close(); 42 | } catch (IOException ignored) { 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/lifecycle/Utils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.lifecycle; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.util.Log; 6 | ; 7 | import androidx.annotation.NonNull; 8 | import androidx.lifecycle.Lifecycle; 9 | 10 | 11 | public final class Utils { 12 | 13 | private static Application sApp; 14 | 15 | private Utils() { 16 | throw new UnsupportedOperationException("u can't instantiate me..."); 17 | } 18 | 19 | /** 20 | * Init utils. 21 | *

Init it in the class of UtilsFileProvider.

22 | * 23 | * @param app application 24 | */ 25 | public static void init(final Application app) { 26 | if (app == null) { 27 | Log.e("Utils", "app is null."); 28 | return; 29 | } 30 | if (sApp == null) { 31 | sApp = app; 32 | UtilsBridge.init(sApp); 33 | return; 34 | } 35 | if (sApp.equals(app)) return; 36 | UtilsBridge.unInit(sApp); 37 | sApp = app; 38 | UtilsBridge.init(sApp); 39 | } 40 | 41 | /** 42 | * Register the status of application changed listener. 43 | * 44 | * @param listener The status of application changed listener 45 | */ 46 | public static void registerAppStatusChangedListener(@NonNull final Utils.OnAppStatusChangedListener listener) { 47 | UtilsBridge.addOnAppStatusChangedListener(listener); 48 | } 49 | 50 | /** 51 | * Unregister the status of application changed listener. 52 | * 53 | * @param listener The status of application changed listener 54 | */ 55 | public static void unregisterAppStatusChangedListener(@NonNull final Utils.OnAppStatusChangedListener listener) { 56 | UtilsBridge.removeOnAppStatusChangedListener(listener); 57 | } 58 | 59 | /** 60 | * app是否处于前台 61 | * @return 是否在前台 62 | */ 63 | public static boolean isAppForeground() { 64 | return UtilsBridge.isAppForeground(); 65 | } 66 | 67 | /** 68 | * Return the Application object. 69 | *

Main process get app by UtilsFileProvider, 70 | * and other process get app by reflect.

71 | * 72 | * @return the Application object 73 | */ 74 | public static Application getApp() { 75 | if (sApp != null) return sApp; 76 | init(UtilsBridge.getApplicationByReflect()); 77 | if (sApp == null) throw new NullPointerException("reflect failed."); 78 | Log.i("Utils", UtilsBridge.getCurrentProcessName() + " reflect app success."); 79 | return sApp; 80 | } 81 | 82 | public interface OnAppStatusChangedListener { 83 | void onForeground(Activity activity); 84 | 85 | void onBackground(Activity activity); 86 | } 87 | 88 | public static class ActivityLifecycleCallbacks { 89 | 90 | public void onActivityCreated(Activity activity) {/**/} 91 | 92 | public void onActivityStarted(Activity activity) {/**/} 93 | 94 | public void onActivityResumed(Activity activity) {/**/} 95 | 96 | public void onActivityPaused(Activity activity) {/**/} 97 | 98 | public void onActivityStopped(Activity activity) {/**/} 99 | 100 | public void onActivityDestroyed(Activity activity) {/**/} 101 | 102 | public void onLifecycleChanged(Activity activity, Lifecycle.Event event) {/**/} 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/lifecycle/UtilsBridge.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.lifecycle; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.content.Context; 6 | 7 | import com.dds.common.utils.KeyboardUtils; 8 | import com.dds.common.utils.ThreadUtils; 9 | 10 | import java.util.List; 11 | 12 | class UtilsBridge { 13 | 14 | static void init(Application app) { 15 | UtilsActivityLifecycleImpl.INSTANCE.init(app); 16 | } 17 | 18 | static void unInit(Application app) { 19 | UtilsActivityLifecycleImpl.INSTANCE.unInit(app); 20 | } 21 | 22 | static void addOnAppStatusChangedListener(final Utils.OnAppStatusChangedListener listener) { 23 | UtilsActivityLifecycleImpl.INSTANCE.addOnAppStatusChangedListener(listener); 24 | } 25 | 26 | static void removeOnAppStatusChangedListener(final Utils.OnAppStatusChangedListener listener) { 27 | UtilsActivityLifecycleImpl.INSTANCE.removeOnAppStatusChangedListener(listener); 28 | } 29 | 30 | static void addActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) { 31 | UtilsActivityLifecycleImpl.INSTANCE.addActivityLifecycleCallbacks(callbacks); 32 | } 33 | 34 | static void removeActivityLifecycleCallbacks(final Utils.ActivityLifecycleCallbacks callbacks) { 35 | UtilsActivityLifecycleImpl.INSTANCE.removeActivityLifecycleCallbacks(callbacks); 36 | } 37 | 38 | static void addActivityLifecycleCallbacks(final Activity activity, 39 | final Utils.ActivityLifecycleCallbacks callbacks) { 40 | UtilsActivityLifecycleImpl.INSTANCE.addActivityLifecycleCallbacks(activity, callbacks); 41 | } 42 | 43 | static void removeActivityLifecycleCallbacks(final Activity activity) { 44 | UtilsActivityLifecycleImpl.INSTANCE.removeActivityLifecycleCallbacks(activity); 45 | } 46 | 47 | static void removeActivityLifecycleCallbacks(final Activity activity, 48 | final Utils.ActivityLifecycleCallbacks callbacks) { 49 | UtilsActivityLifecycleImpl.INSTANCE.removeActivityLifecycleCallbacks(activity, callbacks); 50 | } 51 | 52 | /////////////////////////////////////////////////////////////////////////// 53 | // UtilsActivityLifecycleImpl 54 | /////////////////////////////////////////////////////////////////////////// 55 | static Activity getTopActivity() { 56 | return UtilsActivityLifecycleImpl.INSTANCE.getTopActivity(); 57 | } 58 | 59 | static List getActivityList() { 60 | return UtilsActivityLifecycleImpl.INSTANCE.getActivityList(); 61 | } 62 | 63 | static Application getApplicationByReflect() { 64 | return UtilsActivityLifecycleImpl.INSTANCE.getApplicationByReflect(); 65 | } 66 | 67 | static boolean isAppForeground() { 68 | return UtilsActivityLifecycleImpl.INSTANCE.isAppForeground(); 69 | } 70 | 71 | static boolean isActivityAlive(final Activity activity) { 72 | return ActivityUtils.isActivityAlive(activity); 73 | } 74 | 75 | static Activity getActivityByContext(Context context) { 76 | return ActivityUtils.getActivityByContext(context); 77 | } 78 | 79 | static void runOnUiThread(final Runnable runnable) { 80 | ThreadUtils.runOnUiThread(runnable); 81 | } 82 | 83 | static void runOnUiThreadDelayed(final Runnable runnable, long delayMillis) { 84 | ThreadUtils.runOnUiThreadDelayed(runnable, delayMillis); 85 | } 86 | 87 | static String getCurrentProcessName() { 88 | return ProcessUtils.getCurrentProcessName(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/log/LogDelegate.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.log; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * @author dds 7 | * @date 2016-08-11 8 | */ 9 | public class LogDelegate { 10 | 11 | public interface ILogDelegate { 12 | void e(final String tag, final String msg, final Object... obj); 13 | 14 | void w(final String tag, final String msg, final Object... obj); 15 | 16 | void i(final String tag, final String msg, final Object... obj); 17 | 18 | void d(final String tag, final String msg, final Object... obj); 19 | 20 | void printErrStackTrace(String tag, Throwable tr, final String format, final Object... obj); 21 | } 22 | 23 | public static class DefLogDelegate implements ILogDelegate { 24 | @Override 25 | public void e(String tag, String msg, Object... obj) { 26 | Log.e(tag, String.format(msg, obj)); 27 | 28 | } 29 | 30 | @Override 31 | public void w(String tag, String msg, Object... obj) { 32 | Log.w(tag, String.format(msg, obj)); 33 | } 34 | 35 | @Override 36 | public void i(String tag, String msg, Object... obj) { 37 | Log.i(tag, String.format(msg, obj)); 38 | } 39 | 40 | @Override 41 | public void d(String tag, String msg, Object... obj) { 42 | Log.d(tag, String.format(msg, obj)); 43 | } 44 | 45 | @Override 46 | public void printErrStackTrace(String tag, Throwable tr, String format, Object... obj) { 47 | Log.e(tag, String.format(format, obj)); 48 | Log.e(tag, Log.getStackTraceString(tr)); 49 | } 50 | } 51 | 52 | private static ILogDelegate sDelegate = new DefLogDelegate(); 53 | 54 | public static void setDelegate(ILogDelegate delegate) { 55 | sDelegate = delegate; 56 | } 57 | 58 | public static void e(final String tag, final String msg, final Object... obj) { 59 | if (sDelegate != null) { 60 | sDelegate.e(tag, msg, obj); 61 | } 62 | } 63 | 64 | public static void w(final String tag, final String msg, final Object... obj) { 65 | if (sDelegate != null) { 66 | sDelegate.w(tag, msg, obj); 67 | } 68 | } 69 | 70 | public static void i(final String tag, final String msg, final Object... obj) { 71 | if (sDelegate != null) { 72 | sDelegate.i(tag, msg, obj); 73 | } 74 | } 75 | 76 | public static void d(final String tag, final String msg, final Object... obj) { 77 | if (sDelegate != null) { 78 | sDelegate.d(tag, msg, obj); 79 | } 80 | } 81 | 82 | public static void printErrStackTrace(String tag, Throwable tr, final String format, final Object... obj) { 83 | if (sDelegate != null) { 84 | sDelegate.printErrStackTrace(tag, tr, format, obj); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/net/Apn.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.net; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | import android.net.wifi.WifiInfo; 7 | import android.net.wifi.WifiManager; 8 | import android.telephony.TelephonyManager; 9 | 10 | import java.net.Inet4Address; 11 | import java.net.InetAddress; 12 | import java.net.NetworkInterface; 13 | import java.net.SocketException; 14 | import java.util.Enumeration; 15 | 16 | /** 17 | * 网络相关 18 | */ 19 | public class Apn { 20 | public static final int APN_UNKNOWN = 0; 21 | public static final int APN_2G = 1; 22 | public static final int APN_3G = 2; 23 | public static final int APN_WIFI = 3; 24 | public static final int APN_4G = 4; 25 | 26 | public Apn() { 27 | } 28 | 29 | // 获取网络类型 String 30 | public static String getApnInfo(Context var0) { 31 | String var1 = "unknown"; 32 | ConnectivityManager var2 = (ConnectivityManager) var0.getSystemService(Context.CONNECTIVITY_SERVICE); 33 | NetworkInfo var3 = var2.getActiveNetworkInfo(); 34 | if (var3 != null && var3.isConnectedOrConnecting()) { 35 | switch (var3.getType()) { 36 | case 0: 37 | var1 = var3.getExtraInfo(); 38 | break; 39 | case 1: 40 | var1 = "wifi"; 41 | } 42 | } 43 | 44 | return var1; 45 | } 46 | 47 | // 获取网络类型 int 48 | public static int getApnType(Context var0) { 49 | byte var1 = 0; 50 | ConnectivityManager var2 = (ConnectivityManager) var0.getSystemService(Context.CONNECTIVITY_SERVICE); 51 | NetworkInfo var3 = null; 52 | if (var2 != null) { 53 | var3 = var2.getActiveNetworkInfo(); 54 | } 55 | if (var3 != null && var3.isConnectedOrConnecting()) { 56 | switch (var3.getType()) { 57 | case 0: 58 | switch (var3.getSubtype()) { 59 | case 1: 60 | case 2: 61 | case 4: 62 | case 7: 63 | case 11: 64 | var1 = 1; 65 | return var1; 66 | case 3: 67 | case 5: 68 | case 6: 69 | case 8: 70 | case 9: 71 | case 10: 72 | case 12: 73 | case 14: 74 | case 15: 75 | var1 = 2; 76 | return var1; 77 | case 13: 78 | var1 = 4; 79 | return var1; 80 | default: 81 | var1 = 0; 82 | return var1; 83 | } 84 | case 1: 85 | var1 = 3; 86 | break; 87 | default: 88 | var1 = 0; 89 | } 90 | } 91 | 92 | return var1; 93 | } 94 | 95 | // 网络是否可用 96 | public static boolean isNetworkAvailable(Context context) { 97 | ConnectivityManager var1 = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 98 | NetworkInfo var2 = null; 99 | if (var1 != null) { 100 | var2 = var1.getActiveNetworkInfo(); 101 | } 102 | return var2 != null && (var2.isConnected() || var2.isAvailable()); 103 | } 104 | 105 | // 判断Wifi连接是否可用 106 | public static boolean isWifiActive(Context context) { 107 | ConnectivityManager cm = (ConnectivityManager) context 108 | .getSystemService(Context.CONNECTIVITY_SERVICE); 109 | if (cm != null) { 110 | NetworkInfo[] infos = cm.getAllNetworkInfo(); 111 | if (infos != null) { 112 | for (int i = 0; i < infos.length; i++) { 113 | if (infos[i].getTypeName().equals("WIFI") 114 | && infos[i].isConnected()) { 115 | return true; 116 | } 117 | } 118 | } 119 | } 120 | return false; 121 | } 122 | 123 | // 获取wifi的SSID 124 | public static String getWifiSSID(Context context) { 125 | try { 126 | String var1 = null; 127 | WifiManager var2 = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 128 | WifiInfo var3 = var2.getConnectionInfo(); 129 | if (var3 != null) { 130 | var1 = var3.getBSSID(); 131 | } 132 | 133 | return var1; 134 | } catch (Throwable var4) { 135 | var4.printStackTrace(); 136 | return ""; 137 | } 138 | } 139 | 140 | //判断网络是否为漫游 141 | public static boolean isNetworkRoaming(Context context) { 142 | ConnectivityManager connectivity = (ConnectivityManager) context 143 | .getSystemService(Context.CONNECTIVITY_SERVICE); 144 | if (connectivity != null) { 145 | NetworkInfo info = connectivity.getActiveNetworkInfo(); 146 | if (info != null 147 | && info.getType() == ConnectivityManager.TYPE_MOBILE) { 148 | TelephonyManager tm = (TelephonyManager) context 149 | .getSystemService(Context.TELEPHONY_SERVICE); 150 | if (tm != null && tm.isNetworkRoaming()) { 151 | return true; 152 | } 153 | } 154 | } 155 | return false; 156 | } 157 | 158 | // 获取IPv4地址 159 | public static String getLocalIpAddress() { 160 | try { 161 | for (Enumeration en = NetworkInterface 162 | .getNetworkInterfaces(); en.hasMoreElements(); ) { 163 | NetworkInterface intf = en.nextElement(); 164 | for (Enumeration enumIpAddr = intf 165 | .getInetAddresses(); enumIpAddr.hasMoreElements(); ) { 166 | InetAddress inetAddress = enumIpAddr.nextElement(); 167 | if (!inetAddress.isLoopbackAddress() 168 | && inetAddress instanceof Inet4Address) {// 并保证读取的是ip4地址 169 | return inetAddress.getHostAddress(); 170 | } 171 | } 172 | } 173 | } catch (SocketException e) { 174 | e.printStackTrace(); 175 | } 176 | return null; 177 | } 178 | 179 | //获取MAC地址 180 | public static String getLocalMacAddress(Context context) { 181 | WifiManager wifi = (WifiManager) context 182 | .getSystemService(Context.WIFI_SERVICE); 183 | WifiInfo info = wifi.getConnectionInfo(); 184 | return info.getMacAddress(); 185 | } 186 | 187 | } 188 | 189 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/permission/Permissions.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.permission; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.app.Fragment; 6 | import android.app.FragmentManager; 7 | import android.content.Context; 8 | import android.content.pm.PackageManager; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.os.Process; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.annotation.RequiresApi; 16 | import androidx.core.content.ContextCompat; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import static android.content.pm.PackageManager.PERMISSION_GRANTED; 22 | import static android.os.Build.VERSION_CODES.M; 23 | 24 | /** 25 | * Permission-related helpers Created by dds 26 | */ 27 | public class Permissions { 28 | 29 | 30 | /** 31 | * @param callback will be called if request is not canceled, with either 32 | * {@link PackageManager#PERMISSION_GRANTED} or {@link PackageManager#PERMISSION_DENIED} 33 | */ 34 | public static void request(Activity activity, String permission, Consumer callback) { 35 | if (Build.VERSION.SDK_INT >= M) { 36 | request2(activity, permission, callback); 37 | } else { 38 | if (has(activity, permission)) { 39 | callback.accept(0); 40 | } else { 41 | callback.accept(-1); 42 | } 43 | } 44 | 45 | } 46 | 47 | /** 48 | * @param callback will be called if request is not canceled, with either 49 | * {@link PackageManager#PERMISSION_GRANTED} or {@link PackageManager#PERMISSION_DENIED} 50 | */ 51 | public static void request(Activity activity, String[] permissions, Consumer callback) { 52 | if (Build.VERSION.SDK_INT >= M) { 53 | request2(activity, permissions, callback); 54 | } else { 55 | if (has(activity, permissions)) { 56 | callback.accept(0); 57 | } else { 58 | callback.accept(-1); 59 | } 60 | 61 | } 62 | 63 | } 64 | 65 | @RequiresApi(M) 66 | public static void request2(Activity activity, String permission, Consumer callback) { 67 | final FragmentManager fm = activity.getFragmentManager(); 68 | if (!has(activity, permission)) { 69 | fm.beginTransaction().add(new PermissionRequestFragment(new String[]{permission}, callback), null).commitAllowingStateLoss(); 70 | } else { 71 | callback.accept(PERMISSION_GRANTED); 72 | } 73 | } 74 | 75 | 76 | @RequiresApi(M) 77 | public static void request2(Activity activity, String[] permissions, Consumer callback) { 78 | final FragmentManager fm = activity.getFragmentManager(); 79 | if (!has(activity, permissions)) { 80 | fm.beginTransaction().add(new PermissionRequestFragment(permissions, callback), null).commitAllowingStateLoss(); 81 | } else { 82 | callback.accept(PERMISSION_GRANTED); 83 | } 84 | } 85 | 86 | private static boolean has(Context activity, String... permissions) { 87 | List mPermissionListDenied = new ArrayList<>(); 88 | for (String permission : permissions) { 89 | int result = checkPermission(activity, permission); 90 | if (result != PERMISSION_GRANTED) { 91 | mPermissionListDenied.add(permission); 92 | } 93 | } 94 | return mPermissionListDenied.size() == 0; 95 | } 96 | 97 | private static boolean has(Context context, String permission) { 98 | return context.checkPermission(permission, Process.myPid(), Process.myUid()) == PERMISSION_GRANTED; 99 | } 100 | 101 | private static int checkPermission(Context activity, String permission) { 102 | return ContextCompat.checkSelfPermission(activity, permission); 103 | } 104 | 105 | @RequiresApi(M) 106 | public static class PermissionRequestFragment extends Fragment { 107 | 108 | @SuppressLint("ValidFragment") 109 | public PermissionRequestFragment(@NonNull final String[] permissions, 110 | @NonNull final Consumer callback) { 111 | mPermissions = permissions; 112 | mCallback = callback; 113 | } 114 | 115 | @Override 116 | public void onCreate(@Nullable final Bundle savedInstanceState) { 117 | super.onCreate(savedInstanceState); 118 | if (mPermissions != null) requestPermissions(mPermissions, 0); 119 | 120 | } 121 | 122 | @Override 123 | public void onRequestPermissionsResult(final int request, @NonNull final String[] permissions, 124 | @NonNull final int[] results) { 125 | getFragmentManager().beginTransaction().remove(this).commit(); 126 | if (mCallback == null || results.length == 0/* canceled */) return; 127 | boolean isGrant = true; 128 | for (int result : results) { 129 | if (result != PackageManager.PERMISSION_GRANTED) { 130 | isGrant = false; 131 | break; 132 | } 133 | } 134 | mCallback.accept(isGrant ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED); 135 | } 136 | 137 | public PermissionRequestFragment() { 138 | mPermissions = null; 139 | mCallback = null; 140 | } 141 | 142 | private final @Nullable 143 | String[] mPermissions; 144 | private final @Nullable 145 | Consumer mCallback; 146 | } 147 | 148 | /** 149 | * Represents an operation that accepts a single input argument and returns no 150 | * result. Unlike most other functional interfaces, {@code Consumer} is expected 151 | * to operate via side-effects. 152 | * 153 | * @param the type of the input to the operation 154 | */ 155 | public interface Consumer { 156 | 157 | /** 158 | * Performs this operation on the given argument. 159 | * 160 | * @param t the input argument 161 | */ 162 | void accept(T t); 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/snack/SnackBars.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.snack; 2 | 3 | import android.content.ServiceConnection; 4 | import android.net.Uri; 5 | import android.os.Build; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.CheckResult; 10 | import androidx.browser.customtabs.CustomTabsSession; 11 | 12 | import com.google.android.material.snackbar.BaseTransientBottomBar; 13 | import com.google.android.material.snackbar.Snackbar; 14 | import com.dds.common.R; 15 | 16 | /** 17 | * @author dds 18 | */ 19 | public class SnackBars { 20 | 21 | private static final int DEFAULT_DURATION = 10_000; 22 | private static final int KMaxLines = 3; 23 | 24 | @CheckResult 25 | public static Snackbar make(final View coordinator, final int text_res, final Additional... additional) { 26 | final Snackbar snackbar = Snackbar.make(coordinator, text_res, Snackbar.LENGTH_LONG); 27 | for (final Additional add : additional) if (add != null) add.invoke(snackbar); 28 | return tweak(snackbar); 29 | } 30 | 31 | @CheckResult 32 | public static Snackbar make(final View coordinator, final CharSequence text, final Additional... additional) { 33 | final Snackbar snackbar = Snackbar.make(coordinator, text, Snackbar.LENGTH_LONG); 34 | for (final Additional add : additional) if (add != null) add.invoke(snackbar); 35 | return tweak(snackbar); 36 | } 37 | 38 | @CheckResult 39 | public static Additional lastsForever() { 40 | return new Additional() { 41 | @Override 42 | public void invoke(Snackbar snackbar) { 43 | snackbar.setDuration(BaseTransientBottomBar.LENGTH_LONG); 44 | } 45 | }; 46 | } 47 | 48 | @CheckResult 49 | public static Additional whenSwiped(final Runnable callback) { 50 | return new Additional() { 51 | @Override 52 | public void invoke(Snackbar snackbar) { 53 | snackbar.addCallback(new Snackbar.Callback() { 54 | @Override 55 | public void onDismissed(final Snackbar snackbar, final int event) { 56 | if (event == DISMISS_EVENT_SWIPE) callback.run(); 57 | } 58 | }); 59 | } 60 | }; 61 | } 62 | 63 | @CheckResult 64 | public static Additional withAction(final int label_res, final View.OnClickListener listener) { 65 | return new Additional() { 66 | @Override 67 | public void invoke(Snackbar snackbar) { 68 | snackbar.setAction(label_res, listener); 69 | } 70 | }; 71 | } 72 | 73 | @CheckResult 74 | public static Additional withAction(final CharSequence label, final View.OnClickListener listener) { 75 | return new Additional() { 76 | @Override 77 | public void invoke(Snackbar snackbar) { 78 | snackbar.setAction(label, listener); 79 | } 80 | }; 81 | } 82 | 83 | @CheckResult 84 | public static Additional withLink(final int text_res, final Uri uri) { 85 | return new Additional() { 86 | @Override 87 | public void invoke(Snackbar snackbar) { 88 | withLink(snackbar.getView().getContext().getText(text_res), uri).invoke(snackbar); 89 | } 90 | }; 91 | } 92 | 93 | @CheckResult 94 | public static Additional withLink(final CharSequence text, final Uri uri) { 95 | return new Additional() { 96 | @Override 97 | public void invoke(final Snackbar snackbar) { 98 | snackbar.setAction(text, new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | WebContent.view(v.getContext(), uri); 102 | } 103 | }); // Default action before pre-cache 104 | snackbar.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { 105 | 106 | @Override 107 | public void onViewAttachedToWindow(final View snackbar_view) { 108 | mConnection = WebContent.preload(snackbar_view.getContext(), uri, 109 | new WebContent.OnSessionReadyListener() { 110 | @Override 111 | public void onSessionReady(final CustomTabsSession session) { 112 | snackbar.setAction(text, new View.OnClickListener() { 113 | @Override 114 | public void onClick(View v) { 115 | WebContent.view(v.getContext(), uri, session, null); 116 | } 117 | }); 118 | } 119 | }); 120 | } 121 | 122 | @Override 123 | public void onViewDetachedFromWindow(final View v) { 124 | if (mConnection != null) v.getContext().unbindService(mConnection); 125 | } 126 | 127 | private ServiceConnection mConnection; 128 | }); 129 | } 130 | }; 131 | } 132 | 133 | private static Snackbar tweak(final Snackbar snackbar) { 134 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) snackbar.getView().setZ(999); 135 | final TextView msg_view = snackbar.getView().findViewById(R.id.snackbar_text); 136 | msg_view.setMaxLines(KMaxLines); // Extend max lines 137 | msg_view.setTextColor(0xffffffff); // Workaround the light theme conflict 138 | return snackbar; 139 | } 140 | 141 | public interface Additional { 142 | void invoke(Snackbar instance); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/snack/WebContent.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.snack; 2 | 3 | import android.app.Activity; 4 | import android.content.ActivityNotFoundException; 5 | import android.content.ComponentName; 6 | import android.content.Context; 7 | import android.content.ContextWrapper; 8 | import android.content.Intent; 9 | import android.content.ServiceConnection; 10 | import android.net.Uri; 11 | import android.os.Bundle; 12 | import android.util.Log; 13 | import android.util.TypedValue; 14 | 15 | import androidx.annotation.CheckResult; 16 | import androidx.annotation.Nullable; 17 | import androidx.browser.customtabs.CustomTabsClient; 18 | import androidx.browser.customtabs.CustomTabsIntent; 19 | import androidx.browser.customtabs.CustomTabsServiceConnection; 20 | import androidx.browser.customtabs.CustomTabsSession; 21 | 22 | /** 23 | * Helper class for viewing web content with Chrome Custom Tabs support. 24 | *

25 | * Created by Oasis on 2015/10/4. 26 | */ 27 | public class WebContent { 28 | 29 | private static final String KChromePackageName = "com.android.chrome"; 30 | 31 | /** 32 | * Caller must unbind the returned ServiceConnection when leaving the scope. 33 | */ 34 | public static @CheckResult 35 | @Nullable 36 | ServiceConnection preload(final Context context, final Uri uri, 37 | final @Nullable OnSessionReadyListener listener) { 38 | final CustomTabsServiceConnection connection; 39 | if (!CustomTabsClient.bindCustomTabsService(context, KChromePackageName, connection = new CustomTabsServiceConnection() { 40 | 41 | @Override 42 | public void onCustomTabsServiceConnected(final ComponentName componentName, final CustomTabsClient client) { 43 | Log.d(TAG, "Warming up Chrome custom tabs"); 44 | if (client.warmup(0)) { 45 | final CustomTabsSession session = client.newSession(null); 46 | if (session != null) { 47 | session.mayLaunchUrl(uri, null, null); 48 | if (listener != null) listener.onSessionReady(session); 49 | } 50 | } 51 | } 52 | 53 | @Override 54 | public void onServiceDisconnected(final ComponentName name) { 55 | } 56 | })) return null; 57 | return connection; 58 | } 59 | 60 | public static boolean view(final Context context, final String url) { 61 | Uri uri = Uri.parse(url); 62 | if (uri.isRelative()) uri = Uri.parse("http://" + url); // Append http if no scheme 63 | return view(context, uri); 64 | } 65 | 66 | public static boolean view(final Context context, final Uri uri) { 67 | return view(context, uri, null, null); 68 | } 69 | 70 | public static boolean view(final Context context, final Uri uri, 71 | final @Nullable CustomTabsSession session, 72 | final @Nullable Bundle activity_options) { 73 | if (!uri.isAbsolute() || !uri.isHierarchical()) 74 | throw new IllegalArgumentException("Invalid URL: " + uri); 75 | final Intent intent; 76 | final Activity activity = findActivity(context); 77 | if (activity != null) { // Chrome custom tabs are only supported in 78 | final TypedValue typed_value = new TypedValue(); 79 | activity.getTheme().resolveAttribute(android.R.attr.colorPrimary, typed_value, true); 80 | intent = new CustomTabsIntent.Builder(session).setToolbarColor(typed_value.data).setShowTitle(true).build().intent; 81 | } else intent = new Intent(Intent.ACTION_VIEW).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 82 | intent.setData(uri); 83 | if (intent.getPackage() == null) intent.setSelector(sBrowserSelector); 84 | 85 | try { 86 | startActivity(context, intent, activity_options); 87 | return true; 88 | } catch (final ActivityNotFoundException ignored) { 89 | } 90 | 91 | if (intent.getSelector() != null) { 92 | intent.setSelector(null); // Remove browser selector and try again 93 | try { 94 | startActivity(context, intent, activity_options); 95 | Log.d(TAG, "Browser is launched successfully without browser selector."); 96 | return true; 97 | } catch (final ActivityNotFoundException ignored) { 98 | } 99 | } 100 | 101 | if ("https".equalsIgnoreCase(uri.getScheme())) { // A few browser apps lack the intent-filter for https. 102 | intent.setData(Uri.fromParts("http", uri.getSchemeSpecificPart(), uri.getFragment())); // Fall-back to http 103 | try { 104 | startActivity(context, intent, activity_options); 105 | Log.d(TAG, "Browser is launched successfully after falling back to HTTP URL."); 106 | return true; 107 | } catch (final ActivityNotFoundException exc) { 108 | Log.w(TAG, "Failed to launch browser for URL: " + uri); 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | private static void startActivity(final Context context, final Intent intent, 115 | final @Nullable Bundle activity_options) { 116 | context.startActivity(intent, activity_options); 117 | } 118 | 119 | private static Activity findActivity(Context context) { 120 | while (context instanceof ContextWrapper) { 121 | if (context instanceof Activity) return (Activity) context; 122 | context = ((ContextWrapper) context).getBaseContext(); 123 | } 124 | return null; 125 | } 126 | 127 | private static final Intent sBrowserSelector = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_BROWSER); 128 | private static final String TAG = "WebContent"; 129 | 130 | public interface OnSessionReadyListener { 131 | 132 | /** 133 | * This method may never be called if Chrome Custom Tabs are not supported on device, or session is failed to create. 134 | */ 135 | void onSessionReady(CustomTabsSession session); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/state/IState.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.dds.common.state; 18 | 19 | import android.os.Message; 20 | 21 | /** 22 | * {@hide} 23 | * 24 | * The interface for implementing states in a {@link StateMachine} 25 | */ 26 | public interface IState { 27 | 28 | /** 29 | * Returned by processMessage to indicate the the message was processed. 30 | */ 31 | static final boolean HANDLED = true; 32 | 33 | /** 34 | * Returned by processMessage to indicate the the message was NOT processed. 35 | */ 36 | static final boolean NOT_HANDLED = false; 37 | 38 | /** 39 | * Called when a state is entered. 40 | */ 41 | void enter(); 42 | 43 | /** 44 | * Called when a state is exited. 45 | */ 46 | void exit(); 47 | 48 | /** 49 | * Called when a message is to be processed by the 50 | * state machine. 51 | * 52 | * This routine is never reentered thus no synchronization 53 | * is needed as only one processMessage method will ever be 54 | * executing within a state machine at any given time. This 55 | * does mean that processing by this routine must be completed 56 | * as expeditiously as possible as no subsequent messages will 57 | * be processed until this routine returns. 58 | * 59 | * @param msg to process 60 | * @return HANDLED if processing has completed and NOT_HANDLED 61 | * if the message wasn't processed. 62 | */ 63 | boolean processMessage(Message msg); 64 | 65 | /** 66 | * Name of State for debugging purposes. 67 | * 68 | * @return name of state. 69 | */ 70 | String getName(); 71 | } -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/state/State.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2009 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.dds.common.state; 18 | 19 | import android.os.Message; 20 | 21 | /** 22 | * The class for implementing states in a StateMachine 23 | */ 24 | public class State implements IState { 25 | 26 | /** 27 | * Constructor 28 | */ 29 | protected State() { 30 | } 31 | 32 | /* (non-Javadoc) 33 | * @see IState#enter() 34 | */ 35 | @Override 36 | public void enter() { 37 | } 38 | 39 | /* (non-Javadoc) 40 | * @see IState#exit() 41 | */ 42 | @Override 43 | public void exit() { 44 | } 45 | 46 | /* (non-Javadoc) 47 | * @see IState#processMessage(android.os.Message) 48 | */ 49 | @Override 50 | public boolean processMessage(Message msg) { 51 | return false; 52 | } 53 | 54 | /** 55 | * Name of State for debugging purposes. 56 | * 57 | * This default implementation returns the class name, returning 58 | * the instance name would better in cases where a State class 59 | * is used for multiple states. But normally there is one class per 60 | * state and the class name is sufficient and easy to get. You may 61 | * want to provide a setName or some other mechanism for setting 62 | * another name if the class name is not appropriate. 63 | * 64 | * @see IState#processMessage(Message) 65 | */ 66 | @Override 67 | public String getName() { 68 | String name = getClass().getName(); 69 | int lastDollar = name.lastIndexOf('$'); 70 | return name.substring(lastDollar + 1); 71 | } 72 | } -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/BrightnessUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.content.ContentResolver; 4 | import android.provider.Settings; 5 | import android.view.Window; 6 | import android.view.WindowManager; 7 | 8 | import androidx.annotation.IntRange; 9 | import androidx.annotation.NonNull; 10 | 11 | import com.dds.common.lifecycle.Utils; 12 | 13 | /** 14 | * 屏幕亮度工具类 15 | */ 16 | public final class BrightnessUtils { 17 | 18 | private BrightnessUtils() { 19 | throw new UnsupportedOperationException("u can't instantiate me..."); 20 | } 21 | 22 | /** 23 | * Return whether automatic brightness mode is enabled. 24 | * 25 | * @return {@code true}: yes
{@code false}: no 26 | */ 27 | public static boolean isAutoBrightnessEnabled() { 28 | try { 29 | int mode = Settings.System.getInt( 30 | Utils.getApp().getContentResolver(), 31 | Settings.System.SCREEN_BRIGHTNESS_MODE 32 | ); 33 | return mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; 34 | } catch (Settings.SettingNotFoundException e) { 35 | e.printStackTrace(); 36 | return false; 37 | } 38 | } 39 | 40 | /** 41 | * Enable or disable automatic brightness mode. 42 | *

Must hold {@code }

43 | * 44 | * @param enabled True to enabled, false otherwise. 45 | * @return {@code true}: success
{@code false}: fail 46 | */ 47 | public static boolean setAutoBrightnessEnabled(final boolean enabled) { 48 | return Settings.System.putInt( 49 | Utils.getApp().getContentResolver(), 50 | Settings.System.SCREEN_BRIGHTNESS_MODE, 51 | enabled ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC 52 | : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL 53 | ); 54 | } 55 | 56 | /** 57 | * 获取屏幕亮度 58 | * 59 | * @return 屏幕亮度 0-255 60 | */ 61 | public static int getBrightness() { 62 | try { 63 | return Settings.System.getInt( 64 | Utils.getApp().getContentResolver(), 65 | Settings.System.SCREEN_BRIGHTNESS 66 | ); 67 | } catch (Settings.SettingNotFoundException e) { 68 | e.printStackTrace(); 69 | return 0; 70 | } 71 | } 72 | 73 | /** 74 | * 设置屏幕亮度 75 | *

需添加权限 {@code }

76 | * 并得到授权 77 | * 78 | * @param brightness 亮度值 79 | */ 80 | public static boolean setBrightness(@IntRange(from = 0, to = 255) final int brightness) { 81 | ContentResolver resolver = Utils.getApp().getContentResolver(); 82 | boolean b = Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS, brightness); 83 | resolver.notifyChange(Settings.System.getUriFor("screen_brightness"), null); 84 | return b; 85 | } 86 | 87 | /** 88 | * 设置窗口亮度 89 | * 90 | * @param window 窗口 91 | * @param brightness 亮度值 92 | */ 93 | public static void setWindowBrightness(@NonNull final Window window, 94 | @IntRange(from = 0, to = 255) final int brightness) { 95 | WindowManager.LayoutParams lp = window.getAttributes(); 96 | lp.screenBrightness = brightness / 255f; 97 | window.setAttributes(lp); 98 | } 99 | 100 | /** 101 | * 获取窗口亮度 102 | * 103 | * @param window 窗口 104 | * @return 屏幕亮度 0-255 105 | */ 106 | public static int getWindowBrightness(@NonNull final Window window) { 107 | WindowManager.LayoutParams lp = window.getAttributes(); 108 | float brightness = lp.screenBrightness; 109 | if (brightness < 0) return getBrightness(); 110 | return (int) (brightness * 255); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/CleanUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.dds.common.file.FileDirUtil; 6 | import com.dds.common.file.FileUtils; 7 | 8 | import java.io.File; 9 | 10 | /** 11 | *
 12 |  *     time  : 2016/9/27
 13 |  *     desc  : 清除相关工具类
 14 |  * 
15 | */ 16 | public class CleanUtils { 17 | 18 | private CleanUtils() { 19 | throw new UnsupportedOperationException("u can't instantiate me..."); 20 | } 21 | 22 | /** 23 | * 清除内部缓存 24 | *

/data/data/com.xxx.xxx/cache

25 | * 26 | * @param context 27 | * @return {@code true}: 清除成功
{@code false}: 清除失败 28 | */ 29 | public static boolean cleanInternalCache(Context context) { 30 | return FileUtils.deleteFilesInDir(context.getCacheDir()); 31 | } 32 | 33 | /** 34 | * 清除内部文件 35 | *

/data/data/com.xxx.xxx/files

36 | * 37 | * @param context 38 | * @return {@code true}: 清除成功
{@code false}: 清除失败 39 | */ 40 | public static boolean cleanInternalFiles(Context context) { 41 | return FileUtils.deleteFilesInDir(context.getFilesDir()); 42 | } 43 | 44 | /** 45 | * 清除内部数据库 46 | *

/data/data/com.xxx.xxx/databases

47 | * 48 | * @param context 49 | * @return {@code true}: 清除成功
{@code false}: 清除失败 50 | */ 51 | public static boolean cleanInternalDbs(Context context) { 52 | return FileUtils.deleteFilesInDir(context.getFilesDir().getParent() + File.separator + "databases"); 53 | } 54 | 55 | /** 56 | * 根据名称清除数据库 57 | *

/data/data/com.xxx.xxx/databases/dbName

58 | * 59 | * @param dbName 数据库名称 60 | * @return {@code true}: 清除成功
{@code false}: 清除失败 61 | */ 62 | public static boolean cleanInternalDbByName(Context context, String dbName) { 63 | return context.deleteDatabase(dbName); 64 | } 65 | 66 | /** 67 | * 清除内部SP 68 | *

/data/data/com.xxx.xxx/shared_prefs

69 | * 70 | * @param context 71 | * @return {@code true}: 清除成功
{@code false}: 清除失败 72 | */ 73 | public static boolean cleanInternalSP(Context context) { 74 | return FileUtils.deleteFilesInDir(context.getFilesDir().getParent() + File.separator + "shared_prefs"); 75 | } 76 | 77 | /** 78 | * 清除外部缓存 79 | *

/storage/emulated/0/android/data/com.xxx.xxx/cache

80 | * 81 | * @param context 82 | * @return {@code true}: 清除成功
{@code false}: 清除失败 83 | */ 84 | public static boolean cleanExternalCache(Context context) { 85 | return FileDirUtil.isMountSdcard() && FileUtils.deleteFilesInDir(context.getExternalCacheDir()); 86 | } 87 | 88 | /** 89 | * 清除自定义目录下的文件 90 | * 91 | * @param dirPath 目录路径 92 | * @return {@code true}: 清除成功
{@code false}: 清除失败 93 | */ 94 | public static boolean cleanCustomCache(String dirPath) { 95 | return FileUtils.deleteFilesInDir(dirPath); 96 | } 97 | 98 | /** 99 | * 清除自定义目录下的文件 100 | * 101 | * @param dir 目录 102 | * @return {@code true}: 清除成功
{@code false}: 清除失败 103 | */ 104 | public static boolean cleanCustomCache(File dir) { 105 | return FileUtils.deleteFilesInDir(dir); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/ClipboardUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.content.ClipData; 4 | import android.content.ClipboardManager; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | 9 | /** 10 | *
11 |  *     time  : 2016/9/25
12 |  *     desc  : 剪贴板相关工具类
13 |  * 
14 | */ 15 | public class ClipboardUtils { 16 | 17 | private ClipboardUtils() { 18 | throw new UnsupportedOperationException("u can't instantiate me..."); 19 | } 20 | 21 | /** 22 | * 复制文本到剪贴板 23 | * 24 | * @param text 文本 25 | */ 26 | public static void copyText(Context context,CharSequence text) { 27 | ClipboardManager clipboard = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE); 28 | clipboard.setPrimaryClip(ClipData.newPlainText("text", text)); 29 | } 30 | 31 | /** 32 | * 获取剪贴板的文本 33 | * 34 | * @return 剪贴板的文本 35 | */ 36 | public static CharSequence getText(Context context) { 37 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 38 | ClipData clip = clipboard.getPrimaryClip(); 39 | if (clip != null && clip.getItemCount() > 0) { 40 | return clip.getItemAt(0).coerceToText(context); 41 | } 42 | return null; 43 | } 44 | 45 | /** 46 | * 复制uri到剪贴板 47 | * 48 | * @param uri uri 49 | */ 50 | public static void copyUri(Context context,Uri uri) { 51 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 52 | clipboard.setPrimaryClip(ClipData.newUri(context.getContentResolver(), "uri", uri)); 53 | } 54 | 55 | /** 56 | * 获取剪贴板的uri 57 | * 58 | * @return 剪贴板的uri 59 | */ 60 | public static Uri getUri(Context context) { 61 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 62 | ClipData clip = clipboard.getPrimaryClip(); 63 | if (clip != null && clip.getItemCount() > 0) { 64 | return clip.getItemAt(0).getUri(); 65 | } 66 | return null; 67 | } 68 | 69 | /** 70 | * 复制意图到剪贴板 71 | * 72 | * @param intent 意图 73 | */ 74 | public static void copyIntent(Context context,Intent intent) { 75 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 76 | clipboard.setPrimaryClip(ClipData.newIntent("intent", intent)); 77 | } 78 | 79 | /** 80 | * 获取剪贴板的意图 81 | * 82 | * @return 剪贴板的意图 83 | */ 84 | public static Intent getIntent(Context context) { 85 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 86 | ClipData clip = clipboard.getPrimaryClip(); 87 | if (clip != null && clip.getItemCount() > 0) { 88 | return clip.getItemAt(0).getIntent(); 89 | } 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/CloneUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import java.lang.reflect.Type; 4 | 5 | public final class CloneUtils { 6 | 7 | private CloneUtils() { 8 | throw new UnsupportedOperationException("u can't instantiate me..."); 9 | } 10 | 11 | /** 12 | * Deep clone. 13 | * 14 | * @param data The data. 15 | * @param type The type. 16 | * @param The value type. 17 | * @return The object of cloned. 18 | */ 19 | public static T deepClone(final T data, final Type type) { 20 | try { 21 | return GsonUtils.fromJson(GsonUtils.toJson(data), type); 22 | } catch (Exception e) { 23 | e.printStackTrace(); 24 | return null; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/ConstUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | /** 4 | *
  5 |  *     time  : 2016/8/11
  6 |  *     desc  : 常量相关工具类
  7 |  * 
8 | */ 9 | public class ConstUtils { 10 | 11 | private ConstUtils() { 12 | throw new UnsupportedOperationException("u can't instantiate me..."); 13 | } 14 | 15 | /******************** 存储相关常量 ********************/ 16 | /** 17 | * KB与Byte的倍数 18 | */ 19 | public static final int KB = 1024; 20 | /** 21 | * MB与Byte的倍数 22 | */ 23 | public static final int MB = 1048576; 24 | /** 25 | * GB与Byte的倍数 26 | */ 27 | public static final int GB = 1073741824; 28 | 29 | public enum MemoryUnit { 30 | BYTE, 31 | KB, 32 | MB, 33 | GB 34 | } 35 | 36 | /******************** 时间相关常量 ********************/ 37 | /** 38 | * 秒与毫秒的倍数 39 | */ 40 | public static final int SEC = 1000; 41 | /** 42 | * 分与毫秒的倍数 43 | */ 44 | public static final int MIN = 60000; 45 | /** 46 | * 时与毫秒的倍数 47 | */ 48 | public static final int HOUR = 3600000; 49 | /** 50 | * 天与毫秒的倍数 51 | */ 52 | public static final int DAY = 86400000; 53 | 54 | public enum TimeUnit { 55 | MSEC, 56 | SEC, 57 | MIN, 58 | HOUR, 59 | DAY 60 | } 61 | 62 | /******************** 正则相关常量 ********************/ 63 | /** 64 | * 正则:手机号(简单) 65 | */ 66 | public static final String REGEX_MOBILE_SIMPLE = "^[1]\\d{10}$"; 67 | /** 68 | * 正则:手机号(精确) 69 | *

移动:134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188

70 | *

联通:130、131、132、145、155、156、175、176、185、186

71 | *

电信:133、153、173、177、180、181、189

72 | *

全球星:1349

73 | *

虚拟运营商:170

74 | */ 75 | public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|(147))\\d{8}$"; 76 | /** 77 | * 正则:电话号码 78 | */ 79 | public static final String REGEX_TEL = "^0\\d{2,3}[- ]?\\d{7,8}"; 80 | /** 81 | * 正则:身份证号码15位 82 | */ 83 | public static final String REGEX_ID_CARD15 = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$"; 84 | /** 85 | * 正则:身份证号码18位 86 | */ 87 | public static final String REGEX_ID_CARD18 = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])$"; 88 | /** 89 | * 正则:邮箱 90 | */ 91 | public static final String REGEX_EMAIL = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"; 92 | /** 93 | * 正则:URL 94 | */ 95 | public static final String REGEX_URL = "[a-zA-z]+://[^\\s]*"; 96 | /** 97 | * 正则:汉字 98 | */ 99 | public static final String REGEX_ZH = "^[\\u4e00-\\u9fa5]+$"; 100 | /** 101 | * 正则:用户名,取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位 102 | */ 103 | public static final String REGEX_USERNAME = "^[\\w\\u4e00-\\u9fa5]{6,20}(? 23 | * time : 2016/9/27 24 | * desc : 崩溃相关工具类 25 | * 26 | */ 27 | public class CrashUtils implements UncaughtExceptionHandler { 28 | 29 | private volatile static CrashUtils mInstance; 30 | 31 | private UncaughtExceptionHandler mHandler; 32 | 33 | private boolean mInitialized; 34 | private String crashDir; 35 | private String versionName; 36 | private int versionCode; 37 | 38 | private CrashUtils() { 39 | } 40 | 41 | /** 42 | * 获取单例 43 | *

在Application中初始化{@code CrashUtils.getInstance().init(this);}

44 | *

需添加权限 {@code }

45 | * 46 | * @return 单例 47 | */ 48 | public static CrashUtils getInstance() { 49 | if (mInstance == null) { 50 | synchronized (CrashUtils.class) { 51 | if (mInstance == null) { 52 | mInstance = new CrashUtils(); 53 | } 54 | } 55 | } 56 | return mInstance; 57 | } 58 | 59 | /** 60 | * 初始化 61 | * 62 | * @return {@code true}: 成功
{@code false}: 失败 63 | */ 64 | public boolean init(Context context) { 65 | if (mInitialized) return true; 66 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { 67 | File baseCache = context.getExternalCacheDir(); 68 | if (baseCache == null) return false; 69 | crashDir = baseCache.getPath() + File.separator + "crash" + File.separator; 70 | } else { 71 | File baseCache = context.getCacheDir(); 72 | if (baseCache == null) return false; 73 | crashDir = baseCache.getPath() + File.separator + "crash" + File.separator; 74 | } 75 | try { 76 | PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 77 | versionName = pi.versionName; 78 | versionCode = pi.versionCode; 79 | } catch (PackageManager.NameNotFoundException e) { 80 | e.printStackTrace(); 81 | return false; 82 | } 83 | mHandler = Thread.getDefaultUncaughtExceptionHandler(); 84 | Thread.setDefaultUncaughtExceptionHandler(this); 85 | return mInitialized = true; 86 | } 87 | 88 | @Override 89 | public void uncaughtException(Thread thread, final Throwable throwable) { 90 | String now = new SimpleDateFormat("yy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date()); 91 | final String fullPath = crashDir + now + ".txt"; 92 | if (!FileUtils.createOrExistsFile(fullPath)) return; 93 | new Thread(() -> { 94 | PrintWriter pw = null; 95 | try { 96 | pw = new PrintWriter(new FileWriter(fullPath, false)); 97 | pw.write(getCrashHead()); 98 | throwable.printStackTrace(pw); 99 | Throwable cause = throwable.getCause(); 100 | while (cause != null) { 101 | cause.printStackTrace(pw); 102 | cause = cause.getCause(); 103 | } 104 | } catch (IOException e) { 105 | e.printStackTrace(); 106 | } finally { 107 | CloseUtils.closeIO(pw); 108 | } 109 | }).start(); 110 | if (mHandler != null) { 111 | mHandler.uncaughtException(thread, throwable); 112 | } 113 | } 114 | 115 | /** 116 | * 获取崩溃头 117 | * 118 | * @return 崩溃头 119 | */ 120 | private String getCrashHead() { 121 | return "\n************* Crash Log Head ****************" + 122 | "\nDevice Manufacturer: " + Build.MANUFACTURER +// 设备厂商 123 | "\nDevice Model : " + Build.MODEL +// 设备型号 124 | "\nAndroid Version : " + Build.VERSION.RELEASE +// 系统版本 125 | "\nAndroid SDK : " + Build.VERSION.SDK_INT +// SDK版本 126 | "\nApp VersionName : " + versionName + 127 | "\nApp VersionCode : " + versionCode + 128 | "\n************* Crash Log Head ****************\n\n"; 129 | } 130 | 131 | // 获取崩溃日志目录 132 | public String getCrashDir(Context context) { 133 | return crashDir; 134 | } 135 | 136 | //抓取crash 日志上传服务器管理log日志,比如:腾讯的bugly等等 137 | } 138 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/EncodeUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.os.Build; 4 | import android.text.Html; 5 | import android.util.Base64; 6 | 7 | import java.io.UnsupportedEncodingException; 8 | import java.net.URLDecoder; 9 | import java.net.URLEncoder; 10 | 11 | 12 | public class EncodeUtils { 13 | 14 | private EncodeUtils() { 15 | throw new UnsupportedOperationException("u can't instantiate me..."); 16 | } 17 | 18 | /** 19 | * URL编码 20 | *

若想自己指定字符集,可以使用{@link #urlEncode(String input, String charset)}方法

21 | * 22 | * @param input 要编码的字符 23 | * @return 编码为UTF-8的字符串 24 | */ 25 | public static String urlEncode(String input) { 26 | return urlEncode(input, "UTF-8"); 27 | } 28 | 29 | /** 30 | * URL编码 31 | *

若系统不支持指定的编码字符集,则直接将input原样返回

32 | * 33 | * @param input 要编码的字符 34 | * @param charset 字符集 35 | * @return 编码为字符集的字符串 36 | */ 37 | public static String urlEncode(String input, String charset) { 38 | try { 39 | return URLEncoder.encode(input, charset); 40 | } catch (UnsupportedEncodingException e) { 41 | return input; 42 | } 43 | } 44 | 45 | /** 46 | * URL解码 47 | *

若想自己指定字符集,可以使用 {@link #urlDecode(String input, String charset)}方法

48 | * 49 | * @param input 要解码的字符串 50 | * @return URL解码后的字符串 51 | */ 52 | public static String urlDecode(String input) { 53 | return urlDecode(input, "UTF-8"); 54 | } 55 | 56 | /** 57 | * URL解码 58 | *

若系统不支持指定的解码字符集,则直接将input原样返回

59 | * 60 | * @param input 要解码的字符串 61 | * @param charset 字符集 62 | * @return URL解码为指定字符集的字符串 63 | */ 64 | public static String urlDecode(String input, String charset) { 65 | try { 66 | return URLDecoder.decode(input, charset); 67 | } catch (UnsupportedEncodingException e) { 68 | return input; 69 | } 70 | } 71 | 72 | /** 73 | * Base64编码 74 | * 75 | * @param input 要编码的字符串 76 | * @return Base64编码后的字符串 77 | */ 78 | public static byte[] base64Encode(String input) { 79 | return base64Encode(input.getBytes()); 80 | } 81 | 82 | /** 83 | * Base64编码 84 | * 85 | * @param input 要编码的字节数组 86 | * @return Base64编码后的字符串 87 | */ 88 | public static byte[] base64Encode(byte[] input) { 89 | return Base64.encode(input, Base64.NO_WRAP); 90 | } 91 | 92 | /** 93 | * Base64编码 94 | * 95 | * @param input 要编码的字节数组 96 | * @return Base64编码后的字符串 97 | */ 98 | public static String base64Encode2String(byte[] input) { 99 | return Base64.encodeToString(input, Base64.NO_WRAP); 100 | } 101 | 102 | /** 103 | * Base64解码 104 | * 105 | * @param input 要解码的字符串 106 | * @return Base64解码后的字符串 107 | */ 108 | public static byte[] base64Decode(String input) { 109 | return Base64.decode(input, Base64.NO_WRAP); 110 | } 111 | 112 | /** 113 | * Base64解码 114 | * 115 | * @param input 要解码的字符串 116 | * @return Base64解码后的字符串 117 | */ 118 | public static byte[] base64Decode(byte[] input) { 119 | return Base64.decode(input, Base64.NO_WRAP); 120 | } 121 | 122 | /** 123 | * Base64URL安全编码 124 | *

将Base64中的URL非法字符�?,/=转为其他字符, 见RFC3548

125 | * 126 | * @param input 要Base64URL安全编码的字符串 127 | * @return Base64URL安全编码后的字符串 128 | */ 129 | public static byte[] base64UrlSafeEncode(String input) { 130 | return Base64.encode(input.getBytes(), Base64.URL_SAFE); 131 | } 132 | 133 | /** 134 | * Html编码 135 | * 136 | * @param input 要Html编码的字符串 137 | * @return Html编码后的字符串 138 | */ 139 | public static String htmlEncode(CharSequence input) { 140 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 141 | return Html.escapeHtml(input); 142 | } else { 143 | // 参照Html.escapeHtml()中代码 144 | StringBuilder out = new StringBuilder(); 145 | for (int i = 0, len = input.length(); i < len; i++) { 146 | char c = input.charAt(i); 147 | if (c == '<') { 148 | out.append("<"); 149 | } else if (c == '>') { 150 | out.append(">"); 151 | } else if (c == '&') { 152 | out.append("&"); 153 | } else if (c >= 0xD800 && c <= 0xDFFF) { 154 | if (c < 0xDC00 && i + 1 < len) { 155 | char d = input.charAt(i + 1); 156 | if (d >= 0xDC00 && d <= 0xDFFF) { 157 | i++; 158 | int codepoint = 0x010000 | (int) c - 0xD800 << 10 | (int) d - 0xDC00; 159 | out.append("&#").append(codepoint).append(";"); 160 | } 161 | } 162 | } else if (c > 0x7E || c < ' ') { 163 | out.append("&#").append((int) c).append(";"); 164 | } else if (c == ' ') { 165 | while (i + 1 < len && input.charAt(i + 1) == ' ') { 166 | out.append(" "); 167 | i++; 168 | } 169 | out.append(' '); 170 | } else { 171 | out.append(c); 172 | } 173 | } 174 | return out.toString(); 175 | } 176 | } 177 | 178 | /** 179 | * Html解码 180 | * 181 | * @param input 待解码的字符串 182 | * @return Html解码后的字符串 183 | */ 184 | @SuppressWarnings("deprecation") 185 | public static CharSequence htmlDecode(String input) { 186 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 187 | return Html.fromHtml(input, Html.FROM_HTML_MODE_LEGACY); 188 | } else { 189 | return Html.fromHtml(input); 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/FlashlightUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import static android.hardware.Camera.Parameters.FLASH_MODE_OFF; 4 | import static android.hardware.Camera.Parameters.FLASH_MODE_TORCH; 5 | 6 | import android.content.pm.PackageManager; 7 | import android.graphics.SurfaceTexture; 8 | import android.hardware.Camera; 9 | import android.util.Log; 10 | 11 | import com.dds.common.lifecycle.Utils; 12 | 13 | import java.io.IOException; 14 | 15 | /** 16 | * 闪光灯工具 17 | */ 18 | public final class FlashlightUtils { 19 | 20 | private static Camera mCamera; 21 | private static SurfaceTexture mSurfaceTexture; 22 | 23 | private FlashlightUtils() { 24 | throw new UnsupportedOperationException("u can't instantiate me..."); 25 | } 26 | 27 | /** 28 | * Return whether the device supports flashlight. 29 | * 30 | * @return {@code true}: yes
{@code false}: no 31 | */ 32 | public static boolean isFlashlightEnable() { 33 | return Utils.getApp() 34 | .getPackageManager() 35 | .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); 36 | } 37 | 38 | /** 39 | * Return whether the flashlight is working. 40 | * 41 | * @return {@code true}: yes
{@code false}: no 42 | */ 43 | public static boolean isFlashlightOn() { 44 | if (!init()) return false; 45 | Camera.Parameters parameters = mCamera.getParameters(); 46 | return FLASH_MODE_TORCH.equals(parameters.getFlashMode()); 47 | } 48 | 49 | /** 50 | * Turn on or turn off the flashlight. 51 | * 52 | * @param isOn True to turn on the flashlight, false otherwise. 53 | */ 54 | public static void setFlashlightStatus(final boolean isOn) { 55 | if (!init()) return; 56 | final Camera.Parameters parameters = mCamera.getParameters(); 57 | if (isOn) { 58 | if (!FLASH_MODE_TORCH.equals(parameters.getFlashMode())) { 59 | try { 60 | mCamera.setPreviewTexture(mSurfaceTexture); 61 | mCamera.startPreview(); 62 | parameters.setFlashMode(FLASH_MODE_TORCH); 63 | mCamera.setParameters(parameters); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | } else { 69 | if (!FLASH_MODE_OFF.equals(parameters.getFlashMode())) { 70 | parameters.setFlashMode(FLASH_MODE_OFF); 71 | mCamera.setParameters(parameters); 72 | } 73 | } 74 | } 75 | 76 | /** 77 | * Destroy the flashlight. 78 | */ 79 | public static void destroy() { 80 | if (mCamera == null) return; 81 | mCamera.release(); 82 | mSurfaceTexture = null; 83 | mCamera = null; 84 | } 85 | 86 | private static boolean init() { 87 | if (mCamera == null) { 88 | try { 89 | mCamera = Camera.open(0); 90 | mSurfaceTexture = new SurfaceTexture(0); 91 | } catch (Throwable t) { 92 | Log.e("FlashlightUtils", "init failed: ", t); 93 | return false; 94 | } 95 | } 96 | if (mCamera == null) { 97 | Log.e("FlashlightUtils", "init failed."); 98 | return false; 99 | } 100 | return true; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/MapUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.util.Pair; 4 | 5 | import java.util.Collections; 6 | import java.util.Comparator; 7 | import java.util.HashMap; 8 | import java.util.Hashtable; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | import java.util.TreeMap; 12 | 13 | 14 | public class MapUtils { 15 | 16 | private MapUtils() { 17 | throw new UnsupportedOperationException("u can't instantiate me..."); 18 | } 19 | 20 | /** 21 | * Returns a new read-only map with the specified contents, given as a list of pairs 22 | * where the first value is the key and the second is the value. 23 | * 24 | * @param pairs a list of pairs 25 | * @return a new read-only map with the specified contents 26 | */ 27 | @SafeVarargs 28 | public static Map newUnmodifiableMap(final Pair... pairs) { 29 | return Collections.unmodifiableMap(newHashMap(pairs)); 30 | } 31 | 32 | @SafeVarargs 33 | public static HashMap newHashMap(final Pair... pairs) { 34 | HashMap map = new HashMap<>(); 35 | if (pairs == null || pairs.length == 0) { 36 | return map; 37 | } 38 | for (Pair pair : pairs) { 39 | if (pair == null) continue; 40 | map.put(pair.first, pair.second); 41 | } 42 | return map; 43 | } 44 | 45 | @SafeVarargs 46 | public static LinkedHashMap newLinkedHashMap(final Pair... pairs) { 47 | LinkedHashMap map = new LinkedHashMap<>(); 48 | if (pairs == null || pairs.length == 0) { 49 | return map; 50 | } 51 | for (Pair pair : pairs) { 52 | if (pair == null) continue; 53 | map.put(pair.first, pair.second); 54 | } 55 | return map; 56 | } 57 | 58 | @SafeVarargs 59 | public static TreeMap newTreeMap(final Comparator comparator, 60 | final Pair... pairs) { 61 | if (comparator == null) { 62 | throw new IllegalArgumentException("comparator must not be null"); 63 | } 64 | TreeMap map = new TreeMap<>(comparator); 65 | if (pairs == null || pairs.length == 0) { 66 | return map; 67 | } 68 | for (Pair pair : pairs) { 69 | if (pair == null) continue; 70 | map.put(pair.first, pair.second); 71 | } 72 | return map; 73 | } 74 | 75 | @SafeVarargs 76 | public static Hashtable newHashTable(final Pair... pairs) { 77 | Hashtable map = new Hashtable<>(); 78 | if (pairs == null || pairs.length == 0) { 79 | return map; 80 | } 81 | for (Pair pair : pairs) { 82 | if (pair == null) continue; 83 | map.put(pair.first, pair.second); 84 | } 85 | return map; 86 | } 87 | 88 | /** 89 | * Null-safe check if the specified map is empty. 90 | *

91 | * Null returns true. 92 | * 93 | * @param map the map to check, may be null 94 | * @return true if empty or null 95 | */ 96 | public static boolean isEmpty(Map map) { 97 | return map == null || map.size() == 0; 98 | } 99 | 100 | /** 101 | * Null-safe check if the specified map is not empty. 102 | *

103 | * Null returns false. 104 | * 105 | * @param map the map to check, may be null 106 | * @return true if non-null and non-empty 107 | */ 108 | public static boolean isNotEmpty(Map map) { 109 | return !isEmpty(map); 110 | } 111 | 112 | /** 113 | * Gets the size of the map specified. 114 | * 115 | * @param map The map. 116 | * @return the size of the map specified 117 | */ 118 | public static int size(Map map) { 119 | if (map == null) return 0; 120 | return map.size(); 121 | } 122 | 123 | /** 124 | * Executes the given closure on each element in the collection. 125 | *

126 | * If the input collection or closure is null, there is no change made. 127 | * 128 | * @param map the map to get the input from, may be null 129 | * @param closure the closure to perform, may be null 130 | */ 131 | public static void forAllDo(Map map, Closure closure) { 132 | if (map == null || closure == null) return; 133 | for (Map.Entry kvEntry : map.entrySet()) { 134 | closure.execute(kvEntry.getKey(), kvEntry.getValue()); 135 | } 136 | } 137 | 138 | /** 139 | * Transform the map by applying a Transformer to each element. 140 | *

141 | * If the input map or transformer is null, there is no change made. 142 | * 143 | * @param map the map to get the input from, may be null 144 | * @param transformer the transformer to perform, may be null 145 | */ 146 | public static Map transform(Map map, final Transformer transformer) { 147 | if (map == null || transformer == null) return null; 148 | try { 149 | final Map transMap = map.getClass().newInstance(); 150 | forAllDo(map, new Closure() { 151 | @Override 152 | public void execute(K1 key, V1 value) { 153 | Pair pair = transformer.transform(key, value); 154 | transMap.put(pair.first, pair.second); 155 | } 156 | }); 157 | return transMap; 158 | } catch (IllegalAccessException e) { 159 | e.printStackTrace(); 160 | } catch (InstantiationException e) { 161 | e.printStackTrace(); 162 | } 163 | return null; 164 | } 165 | 166 | /** 167 | * Return the string of map. 168 | * 169 | * @param map The map. 170 | * @return the string of map 171 | */ 172 | public static String toString(Map map) { 173 | if (map == null) return "null"; 174 | return map.toString(); 175 | } 176 | 177 | public interface Closure { 178 | void execute(K key, V value); 179 | } 180 | 181 | public interface Transformer { 182 | Pair transform(K1 k1, V1 v1); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/MetaDataUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.app.Activity; 4 | import android.app.Service; 5 | import android.content.BroadcastReceiver; 6 | import android.content.ComponentName; 7 | import android.content.pm.ActivityInfo; 8 | import android.content.pm.ApplicationInfo; 9 | import android.content.pm.PackageManager; 10 | import android.content.pm.ServiceInfo; 11 | 12 | import androidx.annotation.NonNull; 13 | 14 | import com.dds.common.lifecycle.Utils; 15 | 16 | 17 | public final class MetaDataUtils { 18 | 19 | private MetaDataUtils() { 20 | throw new UnsupportedOperationException("u can't instantiate me..."); 21 | } 22 | 23 | /** 24 | * Return the value of meta-data in application. 25 | * 26 | * @param key The key of meta-data. 27 | * @return the value of meta-data in application 28 | */ 29 | public static String getMetaDataInApp(@NonNull final String key) { 30 | String value = ""; 31 | PackageManager pm = Utils.getApp().getPackageManager(); 32 | String packageName = Utils.getApp().getPackageName(); 33 | try { 34 | ApplicationInfo ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); 35 | value = String.valueOf(ai.metaData.get(key)); 36 | } catch (PackageManager.NameNotFoundException e) { 37 | e.printStackTrace(); 38 | } 39 | return value; 40 | } 41 | 42 | /** 43 | * Return the value of meta-data in activity. 44 | * 45 | * @param activity The activity. 46 | * @param key The key of meta-data. 47 | * @return the value of meta-data in activity 48 | */ 49 | public static String getMetaDataInActivity(@NonNull final Activity activity, 50 | @NonNull final String key) { 51 | return getMetaDataInActivity(activity.getClass(), key); 52 | } 53 | 54 | /** 55 | * Return the value of meta-data in activity. 56 | * 57 | * @param clz The activity class. 58 | * @param key The key of meta-data. 59 | * @return the value of meta-data in activity 60 | */ 61 | public static String getMetaDataInActivity(@NonNull final Class clz, 62 | @NonNull final String key) { 63 | String value = ""; 64 | PackageManager pm = Utils.getApp().getPackageManager(); 65 | ComponentName componentName = new ComponentName(Utils.getApp(), clz); 66 | try { 67 | ActivityInfo ai = pm.getActivityInfo(componentName, PackageManager.GET_META_DATA); 68 | value = String.valueOf(ai.metaData.get(key)); 69 | } catch (PackageManager.NameNotFoundException e) { 70 | e.printStackTrace(); 71 | } 72 | return value; 73 | } 74 | 75 | /** 76 | * Return the value of meta-data in service. 77 | * 78 | * @param service The service. 79 | * @param key The key of meta-data. 80 | * @return the value of meta-data in service 81 | */ 82 | public static String getMetaDataInService(@NonNull final Service service, 83 | @NonNull final String key) { 84 | return getMetaDataInService(service.getClass(), key); 85 | } 86 | 87 | /** 88 | * Return the value of meta-data in service. 89 | * 90 | * @param clz The service class. 91 | * @param key The key of meta-data. 92 | * @return the value of meta-data in service 93 | */ 94 | public static String getMetaDataInService(@NonNull final Class clz, 95 | @NonNull final String key) { 96 | String value = ""; 97 | PackageManager pm = Utils.getApp().getPackageManager(); 98 | ComponentName componentName = new ComponentName(Utils.getApp(), clz); 99 | try { 100 | ServiceInfo info = pm.getServiceInfo(componentName, PackageManager.GET_META_DATA); 101 | value = String.valueOf(info.metaData.get(key)); 102 | } catch (PackageManager.NameNotFoundException e) { 103 | e.printStackTrace(); 104 | } 105 | return value; 106 | } 107 | 108 | /** 109 | * Return the value of meta-data in receiver. 110 | * 111 | * @param receiver The receiver. 112 | * @param key The key of meta-data. 113 | * @return the value of meta-data in receiver 114 | */ 115 | public static String getMetaDataInReceiver(@NonNull final BroadcastReceiver receiver, 116 | @NonNull final String key) { 117 | return getMetaDataInReceiver(receiver.getClass(), key); 118 | } 119 | 120 | /** 121 | * Return the value of meta-data in receiver. 122 | * 123 | * @param clz The receiver class. 124 | * @param key The key of meta-data. 125 | * @return the value of meta-data in receiver 126 | */ 127 | public static String getMetaDataInReceiver(@NonNull final Class clz, 128 | @NonNull final String key) { 129 | String value = ""; 130 | PackageManager pm = Utils.getApp().getPackageManager(); 131 | ComponentName componentName = new ComponentName(Utils.getApp(), clz); 132 | try { 133 | ActivityInfo info = pm.getReceiverInfo(componentName, PackageManager.GET_META_DATA); 134 | value = String.valueOf(info.metaData.get(key)); 135 | } catch (PackageManager.NameNotFoundException e) { 136 | e.printStackTrace(); 137 | } 138 | return value; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/RegexUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import static com.dds.common.utils.ConstUtils.REGEX_DATE; 9 | import static com.dds.common.utils.ConstUtils.REGEX_EMAIL; 10 | import static com.dds.common.utils.ConstUtils.REGEX_ID_CARD15; 11 | import static com.dds.common.utils.ConstUtils.REGEX_ID_CARD18; 12 | import static com.dds.common.utils.ConstUtils.REGEX_IP; 13 | import static com.dds.common.utils.ConstUtils.REGEX_MOBILE_EXACT; 14 | import static com.dds.common.utils.ConstUtils.REGEX_MOBILE_SIMPLE; 15 | import static com.dds.common.utils.ConstUtils.REGEX_TEL; 16 | import static com.dds.common.utils.ConstUtils.REGEX_URL; 17 | import static com.dds.common.utils.ConstUtils.REGEX_USERNAME; 18 | import static com.dds.common.utils.ConstUtils.REGEX_ZH; 19 | 20 | 21 | /** 22 | *

 23 |  *     time  : 2016/8/2
 24 |  *     desc  : 正则相关工具类
 25 |  * 
26 | */ 27 | public class RegexUtils { 28 | 29 | private RegexUtils() { 30 | throw new UnsupportedOperationException("u can't instantiate me..."); 31 | } 32 | 33 | /** 34 | * If u want more please visit http://toutiao.com/i6231678548520731137/ 35 | */ 36 | 37 | /** 38 | * 验证手机号(简单) 39 | * 40 | * @param input 待验证文本 41 | * @return {@code true}: 匹配
{@code false}: 不匹配 42 | */ 43 | public static boolean isMobileSimple(CharSequence input) { 44 | return isMatch(REGEX_MOBILE_SIMPLE, input); 45 | } 46 | 47 | /** 48 | * 验证手机号(精确) 49 | * 50 | * @param input 待验证文本 51 | * @return {@code true}: 匹配
{@code false}: 不匹配 52 | */ 53 | public static boolean isMobileExact(CharSequence input) { 54 | return isMatch(REGEX_MOBILE_EXACT, input); 55 | } 56 | 57 | /** 58 | * 验证电话号码 59 | * 60 | * @param input 待验证文本 61 | * @return {@code true}: 匹配
{@code false}: 不匹配 62 | */ 63 | public static boolean isTel(CharSequence input) { 64 | return isMatch(REGEX_TEL, input); 65 | } 66 | 67 | /** 68 | * 验证身份证号码15位 69 | * 70 | * @param input 待验证文本 71 | * @return {@code true}: 匹配
{@code false}: 不匹配 72 | */ 73 | public static boolean isIDCard15(CharSequence input) { 74 | return isMatch(REGEX_ID_CARD15, input); 75 | } 76 | 77 | /** 78 | * 验证身份证号码18位 79 | * 80 | * @param input 待验证文本 81 | * @return {@code true}: 匹配
{@code false}: 不匹配 82 | */ 83 | public static boolean isIDCard18(CharSequence input) { 84 | return isMatch(REGEX_ID_CARD18, input); 85 | } 86 | 87 | /** 88 | * 验证邮箱 89 | * 90 | * @param input 待验证文本 91 | * @return {@code true}: 匹配
{@code false}: 不匹配 92 | */ 93 | public static boolean isEmail(CharSequence input) { 94 | return isMatch(REGEX_EMAIL, input); 95 | } 96 | 97 | /** 98 | * 验证URL 99 | * 100 | * @param input 待验证文本 101 | * @return {@code true}: 匹配
{@code false}: 不匹配 102 | */ 103 | public static boolean isURL(CharSequence input) { 104 | return isMatch(REGEX_URL, input); 105 | } 106 | 107 | /** 108 | * 验证汉字 109 | * 110 | * @param input 待验证文本 111 | * @return {@code true}: 匹配
{@code false}: 不匹配 112 | */ 113 | public static boolean isZh(CharSequence input) { 114 | return isMatch(REGEX_ZH, input); 115 | } 116 | 117 | /** 118 | * 验证用户名 119 | *

取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位

120 | * 121 | * @param input 待验证文本 122 | * @return {@code true}: 匹配
{@code false}: 不匹配 123 | */ 124 | public static boolean isUsername(CharSequence input) { 125 | return isMatch(REGEX_USERNAME, input); 126 | } 127 | 128 | /** 129 | * 验证yyyy-MM-dd格式的日期校验,已考虑平闰年 130 | * 131 | * @param input 待验证文本 132 | * @return {@code true}: 匹配
{@code false}: 不匹配 133 | */ 134 | public static boolean isDate(CharSequence input) { 135 | return isMatch(REGEX_DATE, input); 136 | } 137 | 138 | /** 139 | * 验证IP地址 140 | * 141 | * @param input 待验证文本 142 | * @return {@code true}: 匹配
{@code false}: 不匹配 143 | */ 144 | public static boolean isIP(CharSequence input) { 145 | return isMatch(REGEX_IP, input); 146 | } 147 | 148 | /** 149 | * 判断是否匹配正则 150 | * 151 | * @param regex 正则表达式 152 | * @param input 要匹配的字符串 153 | * @return {@code true}: 匹配
{@code false}: 不匹配 154 | */ 155 | public static boolean isMatch(String regex, CharSequence input) { 156 | return input != null && input.length() > 0 && Pattern.matches(regex, input); 157 | } 158 | 159 | /** 160 | * 获取正则匹配的部分 161 | * 162 | * @param regex 正则表达式 163 | * @param input 要匹配的字符串 164 | * @return 正则匹配的部分 165 | */ 166 | public static List getMatches(String regex, CharSequence input) { 167 | if (input == null) return null; 168 | List matches = new ArrayList<>(); 169 | Pattern pattern = Pattern.compile(regex); 170 | Matcher matcher = pattern.matcher(input); 171 | while (matcher.find()) { 172 | matches.add(matcher.group()); 173 | } 174 | return matches; 175 | } 176 | 177 | /** 178 | * 获取正则匹配分组 179 | * 180 | * @param input 要分组的字符串 181 | * @param regex 正则表达式 182 | * @return 正则匹配分组 183 | */ 184 | public static String[] getSplits(String input, String regex) { 185 | if (input == null) return null; 186 | return input.split(regex); 187 | } 188 | 189 | /** 190 | * 替换正则匹配的第一部分 191 | * 192 | * @param input 要替换的字符串 193 | * @param regex 正则表达式 194 | * @param replacement 代替者 195 | * @return 替换正则匹配的第一部分 196 | */ 197 | public static String getReplaceFirst(String input, String regex, String replacement) { 198 | if (input == null) return null; 199 | return Pattern.compile(regex).matcher(input).replaceFirst(replacement); 200 | } 201 | 202 | /** 203 | * 替换所有正则匹配的部分 204 | * 205 | * @param input 要替换的字符串 206 | * @param regex 正则表达式 207 | * @param replacement 代替者 208 | * @return 替换所有正则匹配的部分 209 | */ 210 | public static String getReplaceAll(String input, String regex, String replacement) { 211 | if (input == null) return null; 212 | return Pattern.compile(regex).matcher(input).replaceAll(replacement); 213 | } 214 | } -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/RomUtil.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.os.Build; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | 11 | /** 12 | * Created by dds on 2018/3/20. 13 | */ 14 | 15 | public class RomUtil { 16 | private static final String TAG = "RomUtil"; 17 | 18 | public static final String ROM_MIUI = "MIUI"; 19 | public static final String ROM_EMUI = "EMUI"; 20 | public static final String ROM_FLYME = "FLYME"; 21 | public static final String ROM_OPPO = "OPPO"; 22 | public static final String ROM_SMARTISAN = "SMARTISAN"; 23 | 24 | public static final String ROM_VIVO = "VIVO"; 25 | public static final String ROM_QIKU = "QIKU"; 26 | 27 | public static final String ROM_LENOVO = "LENOVO"; 28 | public static final String ROM_SAMSUNG = "SAMSUNG"; 29 | 30 | private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name"; 31 | private static final String KEY_VERSION_EMUI = "ro.build.version.emui"; 32 | private static final String KEY_VERSION_OPPO = "ro.build.version.opporom"; 33 | private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version"; 34 | private static final String KEY_VERSION_VIVO = "ro.vivo.os.version"; 35 | private static final String KEY_VERSION_GIONEE = "ro.gn.sv.version"; 36 | private static final String KEY_VERSION_LENOVO = "ro.lenovo.lvp.version"; 37 | private static final String KEY_VERSION_FLYME = "ro.build.display.id"; 38 | 39 | 40 | private static final String KEY_EMUI_VERSION_CODE = "ro.build.hw_emui_api_level"; 41 | 42 | private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code"; 43 | private static final String KEY_MIUI_HANDY_MODE_SF = "ro.miui.has_handy_mode_sf"; 44 | private static final String KEY_MIUI_REAL_BLUR = "ro.miui.has_real_blur"; 45 | 46 | private static final String KEY_FLYME_PUBLISHED = "ro.flyme.published"; 47 | private static final String KEY_FLYME_FLYME = "ro.meizu.setupwizard.flyme"; 48 | 49 | private static final String KEY_FLYME_ICON_FALG = "persist.sys.use.flyme.icon"; 50 | private static final String KEY_FLYME_SETUP_FALG = "ro.meizu.setupwizard.flyme"; 51 | private static final String KEY_FLYME_PUBLISH_FALG = "ro.flyme.published"; 52 | 53 | private static final String KEY_VIVO_OS_NAME = "ro.vivo.os.name"; 54 | private static final String KEY_VIVO_OS_VERSION = "ro.vivo.os.version"; 55 | private static final String KEY_VIVO_ROM_VERSION = "ro.vivo.rom.version"; 56 | 57 | public static boolean isEmui() { 58 | return check(ROM_EMUI); 59 | } 60 | 61 | public static boolean isMiui() { 62 | return check(ROM_MIUI); 63 | } 64 | 65 | public static boolean isVivo() { 66 | return check(ROM_VIVO); 67 | } 68 | 69 | public static boolean isOppo() { 70 | return check(ROM_OPPO); 71 | } 72 | 73 | public static boolean isFlyme() { 74 | return check(ROM_FLYME); 75 | } 76 | 77 | public static boolean isQiku() { 78 | return check(ROM_QIKU) || check("360"); 79 | } 80 | 81 | public static boolean isSmartisan() { 82 | return check(ROM_SMARTISAN); 83 | } 84 | 85 | private final static String ZTEC2016 = "zte c2016"; 86 | 87 | public static boolean isZTKC2016() { 88 | final String board = android.os.Build.MODEL; 89 | return board != null && board.toLowerCase().contains(ZTEC2016); 90 | } 91 | 92 | private static String sName; 93 | 94 | public static String getName() { 95 | if (sName == null) { 96 | check(""); 97 | } 98 | return sName; 99 | } 100 | 101 | private static String sVersion; 102 | 103 | public static String getVersion() { 104 | if (sVersion == null) { 105 | check(""); 106 | } 107 | return sVersion; 108 | } 109 | 110 | public static boolean check(String rom) { 111 | if (sName != null) { 112 | return sName.equals(rom); 113 | } 114 | 115 | if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) { 116 | sName = ROM_MIUI; 117 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) { 118 | sName = ROM_EMUI; 119 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) { 120 | sName = ROM_OPPO; 121 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) { 122 | sName = ROM_VIVO; 123 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) { 124 | sName = ROM_SMARTISAN; 125 | } else { 126 | sVersion = Build.DISPLAY; 127 | if (sVersion.toUpperCase().contains(ROM_FLYME)) { 128 | sName = ROM_FLYME; 129 | } else { 130 | sVersion = Build.UNKNOWN; 131 | sName = Build.MANUFACTURER.toUpperCase(); 132 | } 133 | } 134 | return sName.equals(rom); 135 | } 136 | 137 | public static String getProp(String name) { 138 | String line = null; 139 | BufferedReader input = null; 140 | try { 141 | Process p = Runtime.getRuntime().exec("getprop " + name); 142 | input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); 143 | line = input.readLine(); 144 | input.close(); 145 | } catch (IOException ex) { 146 | Log.e(TAG, "Unable to read prop " + name, ex); 147 | return null; 148 | } finally { 149 | if (input != null) { 150 | try { 151 | input.close(); 152 | } catch (IOException e) { 153 | e.printStackTrace(); 154 | } 155 | } 156 | } 157 | return line; 158 | } 159 | 160 | 161 | } -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/ShellUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.Closeable; 5 | import java.io.DataOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | import java.util.List; 9 | 10 | public class ShellUtils { 11 | 12 | private ShellUtils() { 13 | throw new UnsupportedOperationException("u can't instantiate me..."); 14 | } 15 | 16 | /** 17 | * 是否是在root下执行命令 18 | * 19 | * @param command 命令 20 | * @param isRoot 是否需要root权限执行 21 | * @return CommandResult 22 | */ 23 | public static CommandResult execCmd(String command, boolean isRoot) { 24 | return execCmd(new String[]{command}, isRoot, true); 25 | } 26 | 27 | /** 28 | * 是否是在root下执行命令 29 | * 30 | * @param commands 多条命令链表 31 | * @param isRoot 是否需要root权限执行 32 | * @return CommandResult 33 | */ 34 | public static CommandResult execCmd(List commands, boolean isRoot) { 35 | return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRoot, true); 36 | } 37 | 38 | /** 39 | * 是否是在root下执行命令 40 | * 41 | * @param commands 多条命令数组 42 | * @param isRoot 是否需要root权限执行 43 | * @return CommandResult 44 | */ 45 | public static CommandResult execCmd(String[] commands, boolean isRoot) { 46 | return execCmd(commands, isRoot, true); 47 | } 48 | 49 | /** 50 | * 是否是在root下执行命令 51 | * 52 | * @param command 命令 53 | * @param isRoot 是否需要root权限执行 54 | * @param isNeedResultMsg 是否需要结果消息 55 | * @return CommandResult 56 | */ 57 | public static CommandResult execCmd(String command, boolean isRoot, boolean isNeedResultMsg) { 58 | return execCmd(new String[]{command}, isRoot, isNeedResultMsg); 59 | } 60 | 61 | /** 62 | * 是否是在root下执行命令 63 | * 64 | * @param commands 命令链表 65 | * @param isRoot 是否需要root权限执行 66 | * @param isNeedResultMsg 是否需要结果消息 67 | * @return CommandResult 68 | */ 69 | public static CommandResult execCmd(List commands, boolean isRoot, boolean isNeedResultMsg) { 70 | return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg); 71 | } 72 | 73 | /** 74 | * 是否是在root下执行命令 75 | * 76 | * @param commands 命令数组 77 | * @param isRoot 是否需要root权限执行 78 | * @param isNeedResultMsg 是否需要结果消息 79 | * @return CommandResult 80 | */ 81 | public static CommandResult execCmd(String[] commands, boolean isRoot, boolean isNeedResultMsg) { 82 | int result = -1; 83 | if (commands == null || commands.length == 0) { 84 | return new CommandResult(result, null, null); 85 | } 86 | Process process = null; 87 | BufferedReader successResult = null; 88 | BufferedReader errorResult = null; 89 | StringBuilder successMsg = null; 90 | StringBuilder errorMsg = null; 91 | DataOutputStream os = null; 92 | try { 93 | process = Runtime.getRuntime().exec(isRoot ? "su" : "sh"); 94 | os = new DataOutputStream(process.getOutputStream()); 95 | for (String command : commands) { 96 | if (command == null) continue; 97 | os.write(command.getBytes()); 98 | os.writeBytes("\n"); 99 | os.flush(); 100 | } 101 | os.writeBytes("exit\n"); 102 | os.flush(); 103 | result = process.waitFor(); 104 | if (isNeedResultMsg) { 105 | successMsg = new StringBuilder(); 106 | errorMsg = new StringBuilder(); 107 | successResult = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); 108 | errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8")); 109 | String s; 110 | while ((s = successResult.readLine()) != null) { 111 | successMsg.append(s); 112 | } 113 | while ((s = errorResult.readLine()) != null) { 114 | errorMsg.append(s); 115 | } 116 | } 117 | } catch (Exception e) { 118 | e.printStackTrace(); 119 | } finally { 120 | closeIO(os, successResult, errorResult); 121 | if (process != null) { 122 | process.destroy(); 123 | } 124 | } 125 | return new CommandResult( 126 | result, 127 | successMsg == null ? null : successMsg.toString(), 128 | errorMsg == null ? null : errorMsg.toString() 129 | ); 130 | } 131 | 132 | private static void closeIO(Closeable... closeables) { 133 | if (closeables == null) return; 134 | for (Closeable closeable : closeables) { 135 | if (closeable != null) { 136 | try { 137 | closeable.close(); 138 | } catch (IOException e) { 139 | e.printStackTrace(); 140 | } 141 | } 142 | } 143 | } 144 | 145 | /** 146 | * 返回的命令结果 147 | */ 148 | public static class CommandResult { 149 | /** 150 | * 结果码 151 | **/ 152 | public int result; 153 | /** 154 | * 成功信息 155 | **/ 156 | public String successMsg; 157 | /** 158 | * 错误信息 159 | **/ 160 | public String errorMsg; 161 | 162 | public CommandResult(int result, String successMsg, String errorMsg) { 163 | this.result = result; 164 | this.successMsg = successMsg; 165 | this.errorMsg = errorMsg; 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/SizeUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.content.res.Resources; 4 | import android.util.DisplayMetrics; 5 | import android.util.TypedValue; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public final class SizeUtils { 10 | 11 | private SizeUtils() { 12 | throw new UnsupportedOperationException("u can't instantiate me..."); 13 | } 14 | 15 | /** 16 | * Value of dp to value of px. 17 | * 18 | * @param dpValue The value of dp. 19 | * @return value of px 20 | */ 21 | public static int dp2px(final float dpValue) { 22 | final float scale = Resources.getSystem().getDisplayMetrics().density; 23 | return (int) (dpValue * scale + 0.5f); 24 | } 25 | 26 | /** 27 | * Value of px to value of dp. 28 | * 29 | * @param pxValue The value of px. 30 | * @return value of dp 31 | */ 32 | public static int px2dp(final float pxValue) { 33 | final float scale = Resources.getSystem().getDisplayMetrics().density; 34 | return (int) (pxValue / scale + 0.5f); 35 | } 36 | 37 | /** 38 | * Value of sp to value of px. 39 | * 40 | * @param spValue The value of sp. 41 | * @return value of px 42 | */ 43 | public static int sp2px(final float spValue) { 44 | final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; 45 | return (int) (spValue * fontScale + 0.5f); 46 | } 47 | 48 | /** 49 | * Value of px to value of sp. 50 | * 51 | * @param pxValue The value of px. 52 | * @return value of sp 53 | */ 54 | public static int px2sp(final float pxValue) { 55 | final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; 56 | return (int) (pxValue / fontScale + 0.5f); 57 | } 58 | 59 | /** 60 | * Converts an unpacked complex data value holding a dimension to its final floating 61 | * point value. The two parameters unit and value 62 | * are as in {@link TypedValue#TYPE_DIMENSION}. 63 | * 64 | * @param value The value to apply the unit to. 65 | * @param unit The unit to convert from. 66 | * @return The complex floating point value multiplied by the appropriate 67 | * metrics depending on its unit. 68 | */ 69 | public static float applyDimension(final float value, final int unit) { 70 | DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); 71 | switch (unit) { 72 | case TypedValue.COMPLEX_UNIT_PX: 73 | return value; 74 | case TypedValue.COMPLEX_UNIT_DIP: 75 | return value * metrics.density; 76 | case TypedValue.COMPLEX_UNIT_SP: 77 | return value * metrics.scaledDensity; 78 | case TypedValue.COMPLEX_UNIT_PT: 79 | return value * metrics.xdpi * (1.0f / 72); 80 | case TypedValue.COMPLEX_UNIT_IN: 81 | return value * metrics.xdpi; 82 | case TypedValue.COMPLEX_UNIT_MM: 83 | return value * metrics.xdpi * (1.0f / 25.4f); 84 | } 85 | return 0; 86 | } 87 | 88 | /** 89 | * Force get the size of view. 90 | *

e.g.

91 | *
 92 |      * SizeUtils.forceGetViewSize(view, new SizeUtils.OnGetSizeListener() {
 93 |      *     Override
 94 |      *     public void onGetSize(final View view) {
 95 |      *         view.getWidth();
 96 |      *     }
 97 |      * });
 98 |      * 
99 | * 100 | * @param view The view. 101 | * @param listener The get size listener. 102 | */ 103 | public static void forceGetViewSize(final View view, final OnGetSizeListener listener) { 104 | view.post(new Runnable() { 105 | @Override 106 | public void run() { 107 | if (listener != null) { 108 | listener.onGetSize(view); 109 | } 110 | } 111 | }); 112 | } 113 | 114 | /** 115 | * Return the width of view. 116 | * 117 | * @param view The view. 118 | * @return the width of view 119 | */ 120 | public static int getMeasuredWidth(final View view) { 121 | return measureView(view)[0]; 122 | } 123 | 124 | /** 125 | * Return the height of view. 126 | * 127 | * @param view The view. 128 | * @return the height of view 129 | */ 130 | public static int getMeasuredHeight(final View view) { 131 | return measureView(view)[1]; 132 | } 133 | 134 | /** 135 | * Measure the view. 136 | * 137 | * @param view The view. 138 | * @return arr[0]: view's width, arr[1]: view's height 139 | */ 140 | public static int[] measureView(final View view) { 141 | ViewGroup.LayoutParams lp = view.getLayoutParams(); 142 | if (lp == null) { 143 | lp = new ViewGroup.LayoutParams( 144 | ViewGroup.LayoutParams.MATCH_PARENT, 145 | ViewGroup.LayoutParams.WRAP_CONTENT 146 | ); 147 | } 148 | int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width); 149 | int lpHeight = lp.height; 150 | int heightSpec; 151 | if (lpHeight > 0) { 152 | heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY); 153 | } else { 154 | heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 155 | } 156 | view.measure(widthSpec, heightSpec); 157 | return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()}; 158 | } 159 | 160 | /////////////////////////////////////////////////////////////////////////// 161 | // interface 162 | /////////////////////////////////////////////////////////////////////////// 163 | 164 | public interface OnGetSizeListener { 165 | void onGetSize(View view); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/ThrowableUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import java.io.PrintWriter; 4 | import java.io.StringWriter; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.StringTokenizer; 8 | 9 | 10 | public class ThrowableUtils { 11 | 12 | private static final String LINE_SEP = System.getProperty("line.separator"); 13 | 14 | private ThrowableUtils() { 15 | throw new UnsupportedOperationException("u can't instantiate me..."); 16 | } 17 | 18 | public static String getFullStackTrace(Throwable throwable) { 19 | final List throwableList = new ArrayList<>(); 20 | while (throwable != null && !throwableList.contains(throwable)) { 21 | throwableList.add(throwable); 22 | throwable = throwable.getCause(); 23 | } 24 | final int size = throwableList.size(); 25 | final List frames = new ArrayList<>(); 26 | List nextTrace = getStackFrameList(throwableList.get(size - 1)); 27 | for (int i = size; --i >= 0; ) { 28 | final List trace = nextTrace; 29 | if (i != 0) { 30 | nextTrace = getStackFrameList(throwableList.get(i - 1)); 31 | removeCommonFrames(trace, nextTrace); 32 | } 33 | if (i == size - 1) { 34 | frames.add(throwableList.get(i).toString()); 35 | } else { 36 | frames.add(" Caused by: " + throwableList.get(i).toString()); 37 | } 38 | frames.addAll(trace); 39 | } 40 | StringBuilder sb = new StringBuilder(); 41 | for (final String element : frames) { 42 | sb.append(element).append(LINE_SEP); 43 | } 44 | return sb.toString(); 45 | } 46 | 47 | private static List getStackFrameList(final Throwable throwable) { 48 | final StringWriter sw = new StringWriter(); 49 | final PrintWriter pw = new PrintWriter(sw, true); 50 | throwable.printStackTrace(pw); 51 | final String stackTrace = sw.toString(); 52 | final StringTokenizer frames = new StringTokenizer(stackTrace, LINE_SEP); 53 | final List list = new ArrayList<>(); 54 | boolean traceStarted = false; 55 | while (frames.hasMoreTokens()) { 56 | final String token = frames.nextToken(); 57 | // Determine if the line starts with at 58 | final int at = token.indexOf("at"); 59 | if (at != -1 && token.substring(0, at).trim().isEmpty()) { 60 | traceStarted = true; 61 | list.add(token); 62 | } else if (traceStarted) { 63 | break; 64 | } 65 | } 66 | return list; 67 | } 68 | 69 | private static void removeCommonFrames(final List causeFrames, final List wrapperFrames) { 70 | int causeFrameIndex = causeFrames.size() - 1; 71 | int wrapperFrameIndex = wrapperFrames.size() - 1; 72 | while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) { 73 | // Remove the frame from the cause trace if it is the same 74 | // as in the wrapper trace 75 | final String causeFrame = causeFrames.get(causeFrameIndex); 76 | final String wrapperFrame = wrapperFrames.get(wrapperFrameIndex); 77 | if (causeFrame.equals(wrapperFrame)) { 78 | causeFrames.remove(causeFrameIndex); 79 | } 80 | causeFrameIndex--; 81 | wrapperFrameIndex--; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/Versions.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager.NameNotFoundException; 6 | 7 | /** 8 | * 版本信息类 9 | */ 10 | public class Versions { 11 | 12 | public static int code(final Context context) { 13 | if (sVersionCode == 0) loadVersionInfo(context); 14 | return sVersionCode; 15 | } 16 | 17 | public static String name(final Context context) { 18 | if (sVersionName == null) loadVersionInfo(context); 19 | return sVersionName; 20 | } 21 | 22 | public static long lastUpdateTime(final Context context) { 23 | if (sLastUpdateTime == 0) loadVersionInfo(context); 24 | return sLastUpdateTime; 25 | } 26 | 27 | private static void loadVersionInfo(final Context context) { 28 | try { 29 | final PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 30 | sVersionCode = info.versionCode; 31 | sVersionName = info.versionName; 32 | sLastUpdateTime = info.lastUpdateTime; 33 | } catch (final NameNotFoundException e) { /* Should never happen */ } 34 | } 35 | 36 | private static int sVersionCode; 37 | private static String sVersionName; 38 | private static long sLastUpdateTime; 39 | } 40 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/VibrateUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | 4 | import static android.Manifest.permission.VIBRATE; 5 | 6 | import android.content.Context; 7 | import android.os.Vibrator; 8 | 9 | import androidx.annotation.RequiresPermission; 10 | 11 | public class VibrateUtils { 12 | 13 | private static Vibrator vibrator; 14 | 15 | private VibrateUtils() { 16 | throw new UnsupportedOperationException("u can't instantiate me..."); 17 | } 18 | 19 | /** 20 | * Vibrate. 21 | *

Must hold {@code }

22 | * 23 | * @param milliseconds The number of milliseconds to vibrate. 24 | */ 25 | @RequiresPermission(VIBRATE) 26 | public static void vibrate(Context context,final long milliseconds) { 27 | Vibrator vibrator = getVibrator(context); 28 | if (vibrator == null) return; 29 | vibrator.vibrate(milliseconds); 30 | } 31 | 32 | /** 33 | * Vibrate. 34 | *

Must hold {@code }

35 | * 36 | * @param pattern An array of longs of times for which to turn the vibrator on or off. 37 | * @param repeat The index into pattern at which to repeat, or -1 if you don't want to repeat. 38 | */ 39 | @RequiresPermission(VIBRATE) 40 | public static void vibrate(Context context,final long[] pattern, final int repeat) { 41 | Vibrator vibrator = getVibrator(context); 42 | if (vibrator == null) return; 43 | vibrator.vibrate(pattern, repeat); 44 | } 45 | 46 | /** 47 | * Cancel vibrate. 48 | *

Must hold {@code }

49 | */ 50 | @RequiresPermission(VIBRATE) 51 | public static void cancel(Context context) { 52 | Vibrator vibrator = getVibrator(context); 53 | if (vibrator == null) return; 54 | vibrator.cancel(); 55 | } 56 | 57 | private static Vibrator getVibrator(Context context) { 58 | if (vibrator == null) { 59 | vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 60 | } 61 | return vibrator; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/ViewUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.text.TextUtils; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import androidx.annotation.LayoutRes; 12 | 13 | import java.util.Locale; 14 | 15 | public class ViewUtils { 16 | 17 | /** 18 | * Set the enabled state of this view. 19 | * 20 | * @param view The view. 21 | * @param enabled True to enabled, false otherwise. 22 | */ 23 | public static void setViewEnabled(View view, boolean enabled) { 24 | setViewEnabled(view, enabled, (View) null); 25 | } 26 | 27 | /** 28 | * Set the enabled state of this view. 29 | * 30 | * @param view The view. 31 | * @param enabled True to enabled, false otherwise. 32 | * @param excludes The excludes. 33 | */ 34 | public static void setViewEnabled(View view, boolean enabled, View... excludes) { 35 | if (view == null) return; 36 | if (excludes != null) { 37 | for (View exclude : excludes) { 38 | if (view == exclude) return; 39 | } 40 | } 41 | if (view instanceof ViewGroup) { 42 | ViewGroup viewGroup = (ViewGroup) view; 43 | int childCount = viewGroup.getChildCount(); 44 | for (int i = 0; i < childCount; i++) { 45 | setViewEnabled(viewGroup.getChildAt(i), enabled, excludes); 46 | } 47 | } 48 | view.setEnabled(enabled); 49 | } 50 | 51 | /** 52 | * @param runnable The runnable 53 | */ 54 | public static void runOnUiThread(final Runnable runnable) { 55 | ThreadUtils.runOnUiThread(runnable); 56 | } 57 | 58 | /** 59 | * @param runnable The runnable. 60 | * @param delayMillis The delay (in milliseconds) until the Runnable will be executed. 61 | */ 62 | public static void runOnUiThreadDelayed(final Runnable runnable, long delayMillis) { 63 | ThreadUtils.runOnUiThreadDelayed(runnable, delayMillis); 64 | } 65 | 66 | /** 67 | * Return whether horizontal layout direction of views are from Right to Left. 68 | * 69 | * @return {@code true}: yes
{@code false}: no 70 | */ 71 | public static boolean isLayoutRtl(Context context) { 72 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 73 | Locale primaryLocale; 74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 75 | primaryLocale = context.getResources().getConfiguration().getLocales().get(0); 76 | } else { 77 | primaryLocale =context.getResources().getConfiguration().locale; 78 | } 79 | return TextUtils.getLayoutDirectionFromLocale(primaryLocale) == View.LAYOUT_DIRECTION_RTL; 80 | } 81 | return false; 82 | } 83 | 84 | /** 85 | * Fix the problem of topping the ScrollView nested ListView/GridView/WebView/RecyclerView. 86 | * 87 | * @param view The root view inner of ScrollView. 88 | */ 89 | public static void fixScrollViewTopping(View view) { 90 | view.setFocusable(false); 91 | ViewGroup viewGroup = null; 92 | if (view instanceof ViewGroup) { 93 | viewGroup = (ViewGroup) view; 94 | } 95 | if (viewGroup == null) { 96 | return; 97 | } 98 | for (int i = 0, n = viewGroup.getChildCount(); i < n; i++) { 99 | View childAt = viewGroup.getChildAt(i); 100 | childAt.setFocusable(false); 101 | if (childAt instanceof ViewGroup) { 102 | fixScrollViewTopping(childAt); 103 | } 104 | } 105 | } 106 | 107 | public static View layoutId2View(Context context,@LayoutRes final int layoutId) { 108 | LayoutInflater inflate = 109 | (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 110 | return inflate.inflate(layoutId, null); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /any_common/src/main/java/com/dds/common/utils/VolumeUtils.java: -------------------------------------------------------------------------------- 1 | package com.dds.common.utils; 2 | 3 | 4 | import android.content.Context; 5 | import android.media.AudioManager; 6 | import android.os.Build; 7 | 8 | /** 9 | * 音量相关 10 | */ 11 | public class VolumeUtils { 12 | /** 13 | * Return the volume. 14 | * 15 | * @param streamType The stream type. 16 | *
    17 | *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • 18 | *
  • {@link AudioManager#STREAM_SYSTEM}
  • 19 | *
  • {@link AudioManager#STREAM_RING}
  • 20 | *
  • {@link AudioManager#STREAM_MUSIC}
  • 21 | *
  • {@link AudioManager#STREAM_ALARM}
  • 22 | *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • 23 | *
  • {@link AudioManager#STREAM_DTMF}
  • 24 | *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • 25 | *
26 | * @return the volume 27 | */ 28 | public static int getVolume(Context context,int streamType) { 29 | AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 30 | //noinspection ConstantConditions 31 | return am.getStreamVolume(streamType); 32 | } 33 | 34 | /** 35 | * Sets media volume.
36 | * 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.
37 | * Setting the value of volume lower than 0 will minimize the media volume. 38 | * 39 | * @param streamType The stream type. 40 | *
    41 | *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • 42 | *
  • {@link AudioManager#STREAM_SYSTEM}
  • 43 | *
  • {@link AudioManager#STREAM_RING}
  • 44 | *
  • {@link AudioManager#STREAM_MUSIC}
  • 45 | *
  • {@link AudioManager#STREAM_ALARM}
  • 46 | *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • 47 | *
  • {@link AudioManager#STREAM_DTMF}
  • 48 | *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • 49 | *
50 | * @param volume The volume. 51 | * @param flags The flags. 52 | *
    53 | *
  • {@link AudioManager#FLAG_SHOW_UI}
  • 54 | *
  • {@link AudioManager#FLAG_ALLOW_RINGER_MODES}
  • 55 | *
  • {@link AudioManager#FLAG_PLAY_SOUND}
  • 56 | *
  • {@link AudioManager#FLAG_REMOVE_SOUND_AND_VIBRATE}
  • 57 | *
  • {@link AudioManager#FLAG_VIBRATE}
  • 58 | *
59 | */ 60 | public static void setVolume(Context context,int streamType, int volume, int flags) { 61 | AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 62 | try { 63 | //noinspection ConstantConditions 64 | am.setStreamVolume(streamType, volume, flags); 65 | } catch (SecurityException ignore) { 66 | } 67 | } 68 | 69 | /** 70 | * Return the maximum volume. 71 | * 72 | * @param streamType The stream type. 73 | *
    74 | *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • 75 | *
  • {@link AudioManager#STREAM_SYSTEM}
  • 76 | *
  • {@link AudioManager#STREAM_RING}
  • 77 | *
  • {@link AudioManager#STREAM_MUSIC}
  • 78 | *
  • {@link AudioManager#STREAM_ALARM}
  • 79 | *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • 80 | *
  • {@link AudioManager#STREAM_DTMF}
  • 81 | *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • 82 | *
83 | * @return the maximum volume 84 | */ 85 | public static int getMaxVolume(Context context,int streamType) { 86 | AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 87 | //noinspection ConstantConditions 88 | return am.getStreamMaxVolume(streamType); 89 | } 90 | 91 | /** 92 | * Return the minimum volume. 93 | * 94 | * @param streamType The stream type. 95 | *
    96 | *
  • {@link AudioManager#STREAM_VOICE_CALL}
  • 97 | *
  • {@link AudioManager#STREAM_SYSTEM}
  • 98 | *
  • {@link AudioManager#STREAM_RING}
  • 99 | *
  • {@link AudioManager#STREAM_MUSIC}
  • 100 | *
  • {@link AudioManager#STREAM_ALARM}
  • 101 | *
  • {@link AudioManager#STREAM_NOTIFICATION}
  • 102 | *
  • {@link AudioManager#STREAM_DTMF}
  • 103 | *
  • {@link AudioManager#STREAM_ACCESSIBILITY}
  • 104 | *
105 | * @return the minimum volume 106 | */ 107 | public static int getMinVolume(Context context,int streamType) { 108 | AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 109 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 110 | //noinspection ConstantConditions 111 | return am.getStreamMinVolume(streamType); 112 | } 113 | return 0; 114 | } 115 | } -------------------------------------------------------------------------------- /any_common/src/test/java/com/dds/common/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.dds.common; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /any_common/src/test/java/com/dds/common/hackTest.java: -------------------------------------------------------------------------------- 1 | package com.dds.common; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by dds on 2019/10/18. 7 | * android_shuai@163.com 8 | */ 9 | public class hackTest { 10 | @Test 11 | public void hackStaticMethod() { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 30 5 | defaultConfig { 6 | applicationId "aaa.aaa.aaademo" 7 | minSdkVersion 21 8 | targetSdkVersion 30 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | } 13 | 14 | compileOptions { 15 | sourceCompatibility JavaVersion.VERSION_1_8 16 | targetCompatibility JavaVersion.VERSION_1_8 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | // test 29 | implementation 'junit:junit:4.12' 30 | androidTestImplementation 'androidx.test:runner:1.2.0' 31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 32 | 33 | 34 | // base 35 | implementation 'androidx.appcompat:appcompat:1.1.0' 36 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 37 | implementation 'androidx.browser:browser:1.2.0' 38 | 39 | // other 40 | implementation 'com.google.android.material:material:1.1.0' 41 | implementation 'net.sourceforge.streamsupport:android-retrostreams:1.7.1' 42 | implementation 'net.sourceforge.streamsupport:android-retrofuture:1.7.1' 43 | implementation project(path: ':any_common') 44 | 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddsbear/AnyTool/e61e70ad3911bf0eb99ffa04858f05cb1f7bdb04/app/release/app-release.apk -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/androidTest/java/com/dds/dddemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.trustmobi.dddemo", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/dds/dddemo/hack/HackTest.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.hack; 2 | 3 | import androidx.test.runner.AndroidJUnit4; 4 | 5 | import com.dds.common.hack.Hack; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import java.io.IOException; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | import static org.junit.Assert.assertNotNull; 14 | 15 | /** 16 | * Created by dds on 2019/10/18. 17 | * android_shuai@163.com 18 | */ 19 | @RunWith(AndroidJUnit4.class) 20 | public class HackTest { 21 | @Test 22 | public void hookConstructorMethod() throws Throwable { 23 | // hook 构造方法,然后执行里面的方法 24 | // Hack.HackedMethod0 constructor = Hack 25 | // .into("com.utils.dddemo.hack.HackDemo") 26 | // .constructor() 27 | // .withoutParams(); 28 | // assertNotNull(constructor); 29 | // 30 | // Object statically = constructor 31 | // .invoke() 32 | // .statically(); 33 | // 34 | // assertNotNull(statically); 35 | 36 | Hack.HackedMethod1 constructor1 = Hack 37 | .into("com.utils.dddemo.hack.HackDemo") 38 | .constructor() 39 | .withParam(int.class); 40 | 41 | assertNotNull(constructor1); 42 | 43 | Object statically1 = constructor1.invoke(1222).statically(); 44 | 45 | assertNotNull(statically1); 46 | } 47 | 48 | @Test 49 | public void hookMethod() throws Throwable { 50 | // Hack.HackedMethod1 constructor1 = Hack 51 | // .into("com.utils.dddemo.hack.HackDemo") 52 | // .constructor() 53 | // .withParam(int.class); 54 | // 55 | // assertNotNull(constructor1); 56 | // 57 | // Object statically1 = constructor1.invoke(1222).statically(); 58 | // 59 | // assertNotNull(statically1); 60 | // 61 | // Hack.HackedMethod0 foo = Hack 62 | // .into("com.utils.dddemo.hack.HackDemo") 63 | // .method("foo") 64 | // .returning(int.class) 65 | // .withoutParams(); 66 | // 67 | // assertNotNull(foo); 68 | // 69 | // assertEquals(1222, (int) foo.invoke().on(statically1)); 70 | 71 | Hack.HackedMethod1 constructor1 = Hack 72 | .into("com.utils.dddemo.hack.HackDemo") 73 | .constructor() 74 | .withParam(int.class); 75 | 76 | assertNotNull(constructor1); 77 | 78 | Object statically1 = constructor1.invoke(1222).statically(); 79 | 80 | assertNotNull(statically1); 81 | 82 | Hack.HackedMethod2 foo = Hack 83 | .into("com.utils.dddemo.hack.HackDemo") 84 | .method("foo") 85 | .returning(int.class) 86 | .withParams(int.class, String.class); 87 | 88 | assertNotNull(foo); 89 | 90 | assertEquals(7, (int) foo.invoke(11, "dds_test").on(statically1)); 91 | } 92 | 93 | @Test 94 | public void hookStaticMethod() throws Throwable { 95 | // hook 静态方法 无参数 无返回值 96 | // Hack.HackedMethod0 method = Hack 97 | // .into("com.utils.dddemo.hack.HackDemo") 98 | // .staticMethod("bar") 99 | // .withoutParams(); 100 | // assertNotNull(method); 101 | // 102 | // method.invoke().statically(); 103 | 104 | 105 | Hack.HackedMethod3 method 106 | = Hack.into("com.utils.dddemo.hack.HackDemo") 107 | .staticMethod("bar") 108 | .throwing(IOException.class) 109 | .withParams(int.class, String.class, Bean.class); 110 | 111 | assertNotNull(method); 112 | 113 | method.invoke(-1, "xyz", new Bean()).statically(); 114 | } 115 | 116 | @Test 117 | public void hookStaticField() throws Throwable { 118 | Hack.HackedTargetField field = Hack.into("com.utils.dddemo.hack.HackDemo") 119 | .staticField("staticField") 120 | .ofType(String.class); 121 | 122 | field.set("dds111111111"); 123 | Hack.HackedMethod0 constructor = Hack 124 | .into("com.utils.dddemo.hack.HackDemo") 125 | .constructor() 126 | .withoutParams(); 127 | 128 | assertNotNull(constructor); 129 | 130 | Object statically = constructor.invoke().statically(); 131 | ((HackDemo) statically).printStaticField(); 132 | 133 | 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/App.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.util.Log; 6 | 7 | import com.dds.common.lifecycle.Utils; 8 | 9 | /** 10 | * Created by dds on 2019/6/14. 11 | * android_shuai@163.com 12 | */ 13 | public class App extends Application implements Utils.OnAppStatusChangedListener { 14 | private static App app; 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | app = this; 20 | 21 | 22 | // background and foreground event 23 | Utils.init(app); 24 | Utils.registerAppStatusChangedListener(this); 25 | } 26 | 27 | public static App getApp() { 28 | return app; 29 | } 30 | 31 | @Override 32 | public void onForeground(Activity activity) { 33 | Log.d("dds_test","onForeground"); 34 | } 35 | 36 | @Override 37 | public void onBackground(Activity activity) { 38 | Log.d("dds_test","onBackground"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo; 2 | 3 | import android.Manifest; 4 | import android.content.pm.PackageManager; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import com.dds.common.Toasts; 11 | import com.dds.common.permission.Permissions; 12 | import com.dds.dddemo.ui.DialogActivity; 13 | import com.dds.dddemo.ui.DrawHelperActivity; 14 | import com.dds.dddemo.ui.HackActivity; 15 | import com.dds.dddemo.ui.MediaPlayerActivity; 16 | import com.dds.dddemo.ui.ToastActivity; 17 | 18 | public class MainActivity extends AppCompatActivity { 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | } 25 | 26 | 27 | // Permission 28 | public void onPermission(View view) { 29 | Permissions.request(this, new String[]{ 30 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 31 | Manifest.permission.READ_EXTERNAL_STORAGE}, integer -> { 32 | if (integer == PackageManager.PERMISSION_GRANTED) { 33 | Toasts.showShort(MainActivity.this, "成功accept : " + integer); 34 | } else { 35 | Toasts.showShort(MainActivity.this, "失败accept : " + integer); 36 | } 37 | }); 38 | 39 | } 40 | 41 | // Dialog 42 | public void onDialog(View view) { 43 | DialogActivity.openActivity(this); 44 | } 45 | 46 | // Toast 47 | public void onToast(View view) { 48 | ToastActivity.openActivity(this); 49 | 50 | 51 | } 52 | 53 | // hook 54 | public void onHook(View view) { 55 | HackActivity.openActivity(this); 56 | } 57 | 58 | 59 | // test JetPack 60 | public void onJetpack(View view) { 61 | // JetPackActivity.openActivity(this); 62 | 63 | } 64 | 65 | 66 | // drawable 67 | public void DrawableHelper(View view) { 68 | DrawHelperActivity.openActivity(this); 69 | 70 | 71 | } 72 | 73 | 74 | public void onTest(View view) { 75 | MediaPlayerActivity.openActivity(this); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/hack/Bean.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.hack; 2 | 3 | /** 4 | * Created by dds on 2019/10/18. 5 | * android_shuai@163.com 6 | */ 7 | public class Bean { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/hack/HackDemo.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.hack; 2 | 3 | import android.util.Log; 4 | 5 | import com.dds.common.log.LogDelegate; 6 | 7 | public class HackDemo { 8 | private int mIntField; 9 | private String mStr; 10 | 11 | private static String staticField = "dds"; 12 | 13 | private HackDemo() { 14 | Log.d("dds_test", "constructor"); 15 | } 16 | 17 | private HackDemo(int x) { 18 | mIntField = x; 19 | Log.d("dds_test", "constructor " + x); 20 | } 21 | 22 | private HackDemo(int x, String str) { 23 | mIntField = x; 24 | mStr = str; 25 | Log.d("dds_test", "constructor " + x); 26 | } 27 | 28 | private int foo() { 29 | Log.d("dds_test", "method :foo"); 30 | return mIntField; 31 | } 32 | 33 | private int foo(int type, String str) { 34 | Log.d("dds_test", "method :foo " + type + "," + str); 35 | return 7; 36 | } 37 | 38 | private static void bar() { 39 | Log.d("dds_test", "static method :bar"); 40 | } 41 | 42 | private static int bar(int type) { 43 | Log.d("dds_test", "static method :bar " + type); 44 | return type; 45 | } 46 | 47 | private static void bar(int type, String name, Bean bean) { 48 | LogDelegate.d("dds_test", "static method :bar type:%d,%s,%s", type, name, bean.toString()); 49 | } 50 | 51 | 52 | public void printStaticField() { 53 | Log.d("dds_test", "printStaticField:" + staticField); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/ui/DialogActivity.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.view.View; 8 | 9 | import androidx.appcompat.app.AppCompatActivity; 10 | 11 | import com.dds.dddemo.R; 12 | import com.dds.common.Dialogs; 13 | import com.dds.common.Toasts; 14 | 15 | public class DialogActivity extends AppCompatActivity { 16 | public static void openActivity(Activity activity) { 17 | Intent intent = new Intent(activity, DialogActivity.class); 18 | activity.startActivity(intent); 19 | } 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_dialog); 25 | } 26 | 27 | public void onDialog(View view) { 28 | Dialogs.buildAlert(this, "title", "content ") 29 | .withOkButton(() -> { 30 | Toasts.showShort(DialogActivity.this, "onDialog"); 31 | }) 32 | .withCancelButton() 33 | .show(); 34 | } 35 | 36 | public void onProgressDialog(View view) { 37 | Dialogs.FluentProgressDialog fluentProgressDialog = Dialogs.buildProgress(this, "转转。。。"); 38 | fluentProgressDialog 39 | .indeterminate() 40 | .nonCancelable() 41 | .start(); 42 | 43 | new Handler().postDelayed(new Runnable() { 44 | @Override 45 | public void run() { 46 | runOnUiThread(new Runnable() { 47 | @Override 48 | public void run() { 49 | fluentProgressDialog.dismiss(); 50 | } 51 | }); 52 | 53 | } 54 | }, 2000); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/ui/DrawHelperActivity.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.drawable.LayerDrawable; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.ImageView; 9 | 10 | import androidx.appcompat.app.AppCompatActivity; 11 | import androidx.core.content.ContextCompat; 12 | 13 | import com.dds.dddemo.R; 14 | import com.dds.common.helper.DrawableHelper; 15 | 16 | public class DrawHelperActivity extends AppCompatActivity { 17 | 18 | private ImageView image; 19 | 20 | public static void openActivity(Activity activity) { 21 | Intent intent = new Intent(activity, DrawHelperActivity.class); 22 | activity.startActivity(intent); 23 | } 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_draw_helper); 29 | image = findViewById(R.id.image); 30 | } 31 | 32 | public void onDisplay(View view) { 33 | 34 | // 创建一个纯色图片 35 | // BitmapDrawable drawableWithSize = DrawableHelper.createDrawableWithSize(getResources(), 200, 300, 10, getColor(R.color.colorPrimary)); 36 | // image.setImageDrawable(drawableWithSize); 37 | 38 | // 创建一个渐变图片 39 | // GradientDrawable circleGradientDrawable = DrawableHelper.createCircleGradientDrawable( 40 | // ContextCompat.getColor(this, R.color.colorAccent), 41 | // ContextCompat.getColor(this, R.color.colorPrimaryDark), 42 | // 10, 1f, 1f); 43 | // image.setImageDrawable(circleGradientDrawable); 44 | LayerDrawable itemSeparatorBg = DrawableHelper.createItemSeparatorBg(ContextCompat.getColor(this, R.color.colorAccent), 45 | ContextCompat.getColor(this, R.color.colorPrimaryDark), 46 | 10, false); 47 | image.setBackground(itemSeparatorBg); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/ui/HackActivity.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import com.dds.dddemo.R; 11 | import com.dds.dddemo.hack.HackDemo; 12 | import com.dds.common.hack.Hack; 13 | import com.dds.common.Toasts; 14 | 15 | import java.io.FileNotFoundException; 16 | import java.io.IOException; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertNotNull; 20 | import static org.junit.Assert.assertNull; 21 | 22 | public class HackActivity extends AppCompatActivity { 23 | private Hack.AssertionException mFailure; 24 | 25 | public static void openActivity(Activity activity) { 26 | Intent intent = new Intent(activity, HackActivity.class); 27 | activity.startActivity(intent); 28 | } 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_hack); 34 | Hack.setAssertionFailureHandler(failure -> mFailure = failure); 35 | } 36 | 37 | public void onHook(View view) { 38 | // --------hack constructor 39 | Hack.HackedMethod1 constructor 40 | = Hack.into(HackDemo.class) 41 | .constructor() 42 | .throwing(IOException.class) 43 | .withParam(int.class); 44 | 45 | assertNotNull(constructor); 46 | try { 47 | 48 | HackDemo simple = constructor 49 | .invoke(5) 50 | .statically(); 51 | assertNotNull(simple); 52 | 53 | // -----------hack method 54 | final Hack.HackedMethod0 foo 55 | = Hack 56 | .into(HackDemo.class) 57 | .method("foo") 58 | .returning(int.class) 59 | .withoutParams(); 60 | 61 | assertNotNull(foo); 62 | 63 | assertEquals(7, (int) foo.invoke().on(simple)); 64 | 65 | // -----------hack method 66 | Hack.HackedMethod0 foo_rt_ex 67 | = Hack 68 | .into(HackDemo.class) 69 | .method("foo") 70 | .returning(int.class) 71 | .throwing(RuntimeException.class) 72 | .withoutParams(); 73 | 74 | 75 | assertNotNull(foo_rt_ex); 76 | 77 | assertEquals(7, (int) foo_rt_ex.invoke().on(simple)); 78 | 79 | // -----------hack method 80 | final Hack.HackedMethod0 foo_ex 81 | = Hack 82 | .into(HackDemo.class) 83 | .method("foo") 84 | .returning(int.class) 85 | .throwing(IOException.class) 86 | .withoutParams(); 87 | 88 | assertNotNull(foo_ex); 89 | 90 | assertEquals(7, (int) foo_ex.invoke().on(simple)); 91 | 92 | // -----------hack staticMethod 93 | final Hack.HackedMethod3 bar 94 | = Hack.into(HackDemo.class) 95 | .staticMethod("bar") 96 | .throwing(IOException.class) 97 | .withParams(int.class, String.class, HackDemo.class); 98 | 99 | assertNotNull(bar); 100 | 101 | bar.invoke(-1, "xyz", simple).statically(); 102 | 103 | // -----------error hack 104 | assertFail(null, 105 | Hack.into(HackDemo.class) 106 | .method("bar") 107 | .throwing(UnsupportedOperationException.class, FileNotFoundException.class) 108 | .withParams(int.class, String.class, HackDemo.class)); 109 | 110 | assertFail(NoSuchMethodException.class, 111 | Hack.into(HackDemo.class) 112 | .method("notExist") 113 | .withoutParams()); 114 | 115 | assertFail(NoSuchMethodException.class, 116 | Hack.into(HackDemo.class) 117 | .method("foo") 118 | .withParam(int.class)); 119 | assertFail(null, 120 | Hack.into(HackDemo.class) 121 | .staticMethod("foo") 122 | .withoutParams()); 123 | assertFail(null, 124 | Hack.into(HackDemo.class) 125 | .method("foo") 126 | .returning(Void.class) 127 | .withoutParams()); 128 | 129 | 130 | Toasts.showShort(this, "Hook Test success !"); 131 | 132 | 133 | } catch (IOException e) { 134 | 135 | Toasts.showShort(this, "IOException"); 136 | } 137 | 138 | 139 | } 140 | 141 | 142 | private void assertFail(final Class failure, final Object hack) { 143 | assertNull(hack); 144 | assertNotNull(mFailure); 145 | if (failure != null) { 146 | assertNotNull(mFailure.getCause()); 147 | assertEquals(failure, mFailure.getCause().getClass()); 148 | } 149 | mFailure = null; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/dds/dddemo/ui/ToastActivity.java: -------------------------------------------------------------------------------- 1 | package com.dds.dddemo.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | 9 | import androidx.appcompat.app.AppCompatActivity; 10 | 11 | import com.google.android.material.snackbar.Snackbar; 12 | import com.dds.dddemo.R; 13 | import com.dds.common.snack.SnackBars; 14 | import com.dds.common.Toasts; 15 | 16 | public class ToastActivity extends AppCompatActivity { 17 | 18 | public static void openActivity(Activity activity) { 19 | Intent intent = new Intent(activity, ToastActivity.class); 20 | activity.startActivity(intent); 21 | } 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_toast); 27 | } 28 | 29 | public void onSnake(View view) { 30 | SnackBars.Additional ad = SnackBars.withLink("百度", Uri.parse("https://www.baidu.com")); 31 | Snackbar snackbar = SnackBars.make(view, "dds", ad); 32 | if (snackbar != null) { 33 | snackbar.show(); 34 | } 35 | 36 | } 37 | 38 | public void onToast(View view) { 39 | Toasts.showLong(this, "Toast......"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 |