├── app
├── .gitignore
├── release
│ ├── app-release.apk
│ └── output.json
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.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
│ │ │ ├── xml
│ │ │ │ └── network_permission_config.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_hack.xml
│ │ │ │ ├── activity_draw_helper.xml
│ │ │ │ ├── activity_toast.xml
│ │ │ │ ├── activity_dialog.xml
│ │ │ │ ├── activity_media_player.xml
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── dds
│ │ │ │ └── dddemo
│ │ │ │ ├── hack
│ │ │ │ ├── Bean.java
│ │ │ │ └── HackDemo.java
│ │ │ │ ├── App.java
│ │ │ │ ├── ui
│ │ │ │ ├── ToastActivity.java
│ │ │ │ ├── DialogActivity.java
│ │ │ │ ├── DrawHelperActivity.java
│ │ │ │ └── HackActivity.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── dds
│ │ │ └── dddemo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── dds
│ │ └── dddemo
│ │ ├── ExampleInstrumentedTest.java
│ │ └── hack
│ │ └── HackTest.java
├── proguard-rules.pro
└── build.gradle
├── any_common
├── .gitignore
├── src
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── dds
│ │ │ └── common
│ │ │ ├── hackTest.java
│ │ │ └── ExampleUnitTest.java
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── dds
│ │ │ │ └── common
│ │ │ │ ├── helper
│ │ │ │ ├── ViewDirection.java
│ │ │ │ ├── ActivityLifecycleCallbacks.java
│ │ │ │ └── KeyboardHelper.java
│ │ │ │ ├── hack
│ │ │ │ └── Supplier.java
│ │ │ │ ├── utils
│ │ │ │ ├── CloneUtils.java
│ │ │ │ ├── Versions.java
│ │ │ │ ├── VibrateUtils.java
│ │ │ │ ├── ClipboardUtils.java
│ │ │ │ ├── CleanUtils.java
│ │ │ │ ├── FlashlightUtils.java
│ │ │ │ ├── ThrowableUtils.java
│ │ │ │ ├── BrightnessUtils.java
│ │ │ │ ├── ViewUtils.java
│ │ │ │ ├── CrashUtils.java
│ │ │ │ ├── ConstUtils.java
│ │ │ │ ├── VolumeUtils.java
│ │ │ │ ├── MetaDataUtils.java
│ │ │ │ ├── ShellUtils.java
│ │ │ │ ├── RomUtil.java
│ │ │ │ ├── SizeUtils.java
│ │ │ │ ├── EncodeUtils.java
│ │ │ │ ├── MapUtils.java
│ │ │ │ └── RegexUtils.java
│ │ │ │ ├── io
│ │ │ │ └── CloseUtils.java
│ │ │ │ ├── Toasts.java
│ │ │ │ ├── state
│ │ │ │ ├── State.java
│ │ │ │ └── IState.java
│ │ │ │ ├── log
│ │ │ │ └── LogDelegate.java
│ │ │ │ ├── Dialogs.java
│ │ │ │ ├── activity
│ │ │ │ └── ActivityUtils2.java
│ │ │ │ ├── lifecycle
│ │ │ │ ├── Utils.java
│ │ │ │ └── UtilsBridge.java
│ │ │ │ ├── file
│ │ │ │ └── FileDirUtil.java
│ │ │ │ ├── snack
│ │ │ │ ├── SnackBars.java
│ │ │ │ └── WebContent.java
│ │ │ │ ├── permission
│ │ │ │ └── Permissions.java
│ │ │ │ └── net
│ │ │ │ └── Apn.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── dds
│ │ └── common
│ │ └── ExampleInstrumentedTest.java
├── README.md
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── art
└── anytool2.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradlew.bat
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/any_common/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':any_common'
3 |
4 |
--------------------------------------------------------------------------------
/art/anytool2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddsbear/AnyTool/HEAD/art/anytool2.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddsbear/AnyTool/HEAD/gradle.properties
--------------------------------------------------------------------------------
/app/release/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddsbear/AnyTool/HEAD/app/release/app-release.apk
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
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 Must hold {@code Must hold {@code Must hold {@code /data/data/com.xxx.xxx/cache /data/data/com.xxx.xxx/files /data/data/com.xxx.xxx/databases /data/data/com.xxx.xxx/databases/dbName /data/data/com.xxx.xxx/shared_prefs /storage/emulated/0/android/data/com.xxx.xxx/cache Init it in the class of UtilsFileProvider. Main process get app by UtilsFileProvider,
70 | * and other process get app by reflect. Must hold {@code 需添加权限 {@code 在Application中初始化{@code CrashUtils.getInstance().init(this);} 需添加权限 {@code 移动:134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188 联通:130、131、132、145、155、156、175、176、185、186 电信:133、153、173、177、180、181、189 全球星:1349 虚拟运营商:170 e.g. 若想自己指定字符集,可以使用{@link #urlEncode(String input, String charset)}方法 若系统不支持指定的编码字符集,则直接将input原样返回 若想自己指定字符集,可以使用 {@link #urlDecode(String input, String charset)}方法 若系统不支持指定的解码字符集,则直接将input原样返回 将Base64中的URL非法字符�?,/=转为其他字符, 见RFC3548
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
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/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
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
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 取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位
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/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
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/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/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
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 | *
{@code false}: 清除失败
28 | */
29 | public static boolean cleanInternalCache(Context context) {
30 | return FileUtils.deleteFilesInDir(context.getCacheDir());
31 | }
32 |
33 | /**
34 | * 清除内部文件
35 | *
{@code false}: 清除失败
39 | */
40 | public static boolean cleanInternalFiles(Context context) {
41 | return FileUtils.deleteFilesInDir(context.getFilesDir());
42 | }
43 |
44 | /**
45 | * 清除内部数据库
46 | *
{@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 | *
{@code false}: 清除失败
61 | */
62 | public static boolean cleanInternalDbByName(Context context, String dbName) {
63 | return context.deleteDatabase(dbName);
64 | }
65 |
66 | /**
67 | * 清除内部SP
68 | *
{@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 | *
{@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/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 | *
{@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/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
{@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 | *
{@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 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 |
--------------------------------------------------------------------------------
/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/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
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 | *
{@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/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 | *
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 | *
50 | * @param volume The volume.
51 | * @param flags The flags.
52 | *
53 | *
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 | *
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 | *
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/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 extends Activity> 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 extends Service> 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 extends BroadcastReceiver> 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 |
--------------------------------------------------------------------------------
/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
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/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 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/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 | *
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 | *
{@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