titles) {
55 | this.titles = titles;
56 | }
57 |
58 | @Override
59 | public int getItemPosition(Object object) {
60 | return POSITION_NONE;
61 | }
62 |
63 | @Override
64 | public int getCount() {
65 | return fragments != null ? fragments.size() : 0;
66 | }
67 |
68 | @Override
69 | public CharSequence getPageTitle(int position) {
70 | if (titles == null) {
71 | return null;
72 | }
73 | return titles.get(position);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/statusbar/IStatusBar.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.statusbar;
2 |
3 | import android.app.Activity;
4 |
5 | /**
6 | * 状态栏字体颜色
7 | *
8 | * @author hiphonezhu@gmail.com
9 | * @version [AndroidLibrary, 2018-3-6]
10 | */
11 | public interface IStatusBar {
12 | boolean setStatusBarLightMode(Activity activity, boolean isFontColorDark);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/statusbar/StatusBarFontHelper.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.statusbar;
2 |
3 | import android.app.Activity;
4 | import android.os.Build;
5 | import androidx.annotation.IntDef;
6 |
7 | import library.common.framework.ui.statusbar.impl.AndroidMStatusBar;
8 | import library.common.framework.ui.statusbar.impl.FlymeStatusBar;
9 | import library.common.framework.ui.statusbar.impl.MIUIStatusBar;
10 |
11 | import java.lang.annotation.Retention;
12 | import java.lang.annotation.RetentionPolicy;
13 |
14 | /**
15 | * 状态栏字体颜色 Helper
16 | *
17 | * @author hiphonezhu@gmail.com
18 | * @version [AndroidLibrary, 2018-3-6]
19 | */
20 | public class StatusBarFontHelper {
21 | @IntDef({
22 | OTHER,
23 | MIUI,
24 | FLYME,
25 | ANDROID_M
26 | })
27 | @Retention(RetentionPolicy.SOURCE)
28 | public @interface SystemType {
29 |
30 | }
31 |
32 | public static final int OTHER = -1;
33 | public static final int MIUI = 1;
34 | public static final int FLYME = 2;
35 | public static final int ANDROID_M = 3;
36 |
37 |
38 | /**
39 | * 设置状态栏黑色字体图标,
40 | * 适配4.4以上版本MIUI、Flyme和6.0以上版本其他Android
41 | *
42 | * @param activity
43 | * @param isFontColorDark
44 | * @return 1:MIUI 2:Flyme 3:android6.0
45 | */
46 | public static int setStatusBarMode(Activity activity, boolean isFontColorDark) {
47 | @SystemType int result = 0;
48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
49 | if (new MIUIStatusBar().setStatusBarLightMode(activity, isFontColorDark)) {
50 | result = MIUI;
51 | } else if (new FlymeStatusBar().setStatusBarLightMode(activity, isFontColorDark)) {
52 | result = FLYME;
53 | } else if (new AndroidMStatusBar().setStatusBarLightMode(activity, isFontColorDark)) {
54 | result = ANDROID_M;
55 | }
56 | }
57 | return result;
58 | }
59 |
60 | /**
61 | * 已知系统类型时,设置状态栏黑色字体图标。
62 | * 适配4.4以上版本MIUI6、Flyme和6.0以上版本其他Android
63 | *
64 | * @param activity
65 | * @param type 1:MIUI 2:Flyme 3:android6.0
66 | */
67 | public static void setLightMode(Activity activity, @SystemType int type) {
68 | setStatusBarMode(activity, type, true);
69 |
70 | }
71 |
72 | private static void setStatusBarMode(Activity activity, @SystemType int type, boolean isFontColorDark) {
73 | if (type == MIUI) {
74 | new MIUIStatusBar().setStatusBarLightMode(activity, isFontColorDark);
75 | } else if (type == FLYME) {
76 | new FlymeStatusBar().setStatusBarLightMode(activity, isFontColorDark);
77 | } else if (type == ANDROID_M) {
78 | new AndroidMStatusBar().setStatusBarLightMode(activity, isFontColorDark);
79 | }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/statusbar/impl/AndroidMStatusBar.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.statusbar.impl;
2 |
3 | import android.app.Activity;
4 | import android.os.Build;
5 | import android.view.View;
6 |
7 | import library.common.framework.ui.statusbar.IStatusBar;
8 |
9 | /**
10 | * 6.0状态栏字体颜色
11 | *
12 | * @author hiphonezhu@gmail.com
13 | * @version [AndroidLibrary, 2018-3-6]
14 | */
15 | public class AndroidMStatusBar implements IStatusBar {
16 | /**
17 | * @param activity
18 | * @param isFontColorDark
19 | * @return if version is lager than M
20 | */
21 | @Override
22 | public boolean setStatusBarLightMode(Activity activity, boolean isFontColorDark) {
23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
24 | if (isFontColorDark) {
25 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
26 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
27 | } else {
28 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
29 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
30 | }
31 | return true;
32 | }
33 | return false;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/statusbar/impl/FlymeStatusBar.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.statusbar.impl;
2 |
3 | import android.app.Activity;
4 | import android.view.Window;
5 | import android.view.WindowManager;
6 |
7 | import library.common.framework.ui.statusbar.IStatusBar;
8 |
9 | import java.lang.reflect.Field;
10 |
11 | /**
12 | * 4.4以上版本 Flyme 状态栏字体颜色
13 | *
14 | * @author hiphonezhu@gmail.com
15 | * @version [AndroidLibrary, 2018-3-6]
16 | */
17 | public class FlymeStatusBar implements IStatusBar {
18 |
19 | /**
20 | * 设置状态栏图标为深色和魅族特定的文字风格
21 | * 可以用来判断是否为Flyme用户
22 | *
23 | * @param activity
24 | * @param isFontColorDark 是否把状态栏字体及图标颜色设置为深色
25 | * @return boolean 成功执行返回true
26 | */
27 | @Override
28 | public boolean setStatusBarLightMode(Activity activity, boolean isFontColorDark) {
29 | Window window = activity.getWindow();
30 | boolean result = false;
31 | if (window != null) {
32 | try {
33 | WindowManager.LayoutParams lp = window.getAttributes();
34 | Field darkFlag = WindowManager.LayoutParams.class
35 | .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
36 | Field meizuFlags = WindowManager.LayoutParams.class
37 | .getDeclaredField("meizuFlags");
38 | darkFlag.setAccessible(true);
39 | meizuFlags.setAccessible(true);
40 | int bit = darkFlag.getInt(null);
41 | int value = meizuFlags.getInt(lp);
42 | if (isFontColorDark) {
43 | value |= bit;
44 | } else {
45 | value &= ~bit;
46 | }
47 | meizuFlags.setInt(lp, value);
48 | window.setAttributes(lp);
49 | result = true;
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | return result;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/statusbar/impl/MIUIStatusBar.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.statusbar.impl;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.view.Window;
6 |
7 | import library.common.framework.ui.statusbar.IStatusBar;
8 |
9 | import java.lang.reflect.Field;
10 | import java.lang.reflect.Method;
11 |
12 | /**
13 | * 4.4以上版本 MIUI 状态栏字体颜色
14 | *
15 | * @author hiphonezhu@gmail.com
16 | * @version [AndroidLibrary, 2018-3-6]
17 | */
18 | public class MIUIStatusBar implements IStatusBar {
19 |
20 | /**
21 | * 设置状态栏字体图标为深色,需要MIUI6以上
22 | *
23 | * @param activity
24 | * @param isFontColorDark 是否把状态栏字体及图标颜色设置为深色
25 | * @return boolean 成功执行返回true
26 | */
27 | @Override
28 | public boolean setStatusBarLightMode(Activity activity, boolean isFontColorDark) {
29 | Window window = activity.getWindow();
30 | boolean result = false;
31 | if (window != null) {
32 | Class clazz = window.getClass();
33 | try {
34 | int darkModeFlag = 0;
35 | @SuppressLint("PrivateApi") Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
36 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
37 | darkModeFlag = field.getInt(layoutParams);
38 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
39 | if (isFontColorDark) {
40 | extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
41 | } else {
42 | extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
43 | }
44 | result = true;
45 | } catch (Exception e) {
46 | e.printStackTrace();
47 | }
48 | }
49 | return result;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/swipeback/Utils.java:
--------------------------------------------------------------------------------
1 |
2 | package library.common.framework.ui.swipeback;
3 |
4 | import android.annotation.SuppressLint;
5 | import android.app.Activity;
6 | import android.app.ActivityOptions;
7 | import android.os.Build;
8 |
9 | import java.lang.reflect.Method;
10 |
11 | /**
12 | * Created by Chaojun Wang on 6/9/14.
13 | */
14 | public class Utils {
15 | private Utils() {
16 | }
17 |
18 | /**
19 | * Convert a translucent themed Activity
20 | * {@link android.R.attr#windowIsTranslucent} to a fullscreen opaque
21 | * Activity.
22 | *
23 | * Call this whenever the background of a translucent Activity has changed
24 | * to become opaque. Doing so will allow the {@link android.view.Surface} of
25 | * the Activity behind to be released.
26 | *
27 | * This call has no effect on non-translucent activities or on activities
28 | * with the {@link android.R.attr#windowIsFloating} attribute.
29 | */
30 | public static void convertActivityFromTranslucent(Activity activity) {
31 | try {
32 | Method method = Activity.class.getDeclaredMethod("convertFromTranslucent");
33 | method.setAccessible(true);
34 | method.invoke(activity);
35 | } catch (Throwable t) {
36 | }
37 | }
38 |
39 | /**
40 | * Convert a translucent themed Activity
41 | * {@link android.R.attr#windowIsTranslucent} back from opaque to
42 | * translucent following a call to
43 | * {@link #convertActivityFromTranslucent(Activity)} .
44 | *
45 | * Calling this allows the Activity behind this one to be seen again. Once
46 | * all such Activities have been redrawn
47 | *
48 | * This call has no effect on non-translucent activities or on activities
49 | * with the {@link android.R.attr#windowIsFloating} attribute.
50 | */
51 | public static void convertActivityToTranslucent(Activity activity) {
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
53 | convertActivityToTranslucentAfterL(activity);
54 | } else {
55 | convertActivityToTranslucentBeforeL(activity);
56 | }
57 | }
58 |
59 | /**
60 | * Calling the convertToTranslucent method on platforms before Android 5.0
61 | */
62 | public static void convertActivityToTranslucentBeforeL(Activity activity) {
63 | try {
64 | Class>[] classes = Activity.class.getDeclaredClasses();
65 | Class> translucentConversionListenerClazz = null;
66 | for (Class clazz : classes) {
67 | if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
68 | translucentConversionListenerClazz = clazz;
69 | }
70 | }
71 | Method method = Activity.class.getDeclaredMethod("convertToTranslucent",
72 | translucentConversionListenerClazz);
73 | method.setAccessible(true);
74 | method.invoke(activity, new Object[] {
75 | null
76 | });
77 | } catch (Throwable t) {
78 | }
79 | }
80 |
81 | /**
82 | * Calling the convertToTranslucent method on platforms after Android 5.0
83 | */
84 | private static void convertActivityToTranslucentAfterL(Activity activity) {
85 | try {
86 | @SuppressLint("DiscouragedPrivateApi") Method getActivityOptions = Activity.class.getDeclaredMethod("getActivityOptions");
87 | getActivityOptions.setAccessible(true);
88 | Object options = getActivityOptions.invoke(activity);
89 |
90 | Class>[] classes = Activity.class.getDeclaredClasses();
91 | Class> translucentConversionListenerClazz = null;
92 | for (Class clazz : classes) {
93 | if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
94 | translucentConversionListenerClazz = clazz;
95 | }
96 | }
97 | Method convertToTranslucent = Activity.class.getDeclaredMethod("convertToTranslucent",
98 | translucentConversionListenerClazz, ActivityOptions.class);
99 | convertToTranslucent.setAccessible(true);
100 | convertToTranslucent.invoke(activity, null, options);
101 | } catch (Throwable t) {
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/swipeback/app/SwipeBackActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package library.common.framework.ui.swipeback.app;
3 |
4 | import android.os.Bundle;
5 | import androidx.annotation.ColorInt;
6 | import androidx.appcompat.app.AppCompatActivity;
7 | import android.view.View;
8 |
9 | import library.common.framework.ui.swipeback.SwipeBackLayout;
10 | import library.common.framework.ui.swipeback.Utils;
11 | import library.common.util.APKUtils;
12 |
13 | public class SwipeBackActivity extends AppCompatActivity implements SwipeBackActivityBase {
14 | private SwipeBackActivityHelper mHelper;
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | mHelper = new SwipeBackActivityHelper(this);
20 | mHelper.onActivityCreate();
21 |
22 | getSwipeBackLayout().addSwipeListener(new SwipeBackLayout.SwipeListener() {
23 | @Override
24 | public void onScrollStateChange(int state, float scrollPercent) {
25 |
26 | }
27 |
28 | @Override
29 | public void onEdgeTouch(int edgeFlag) {
30 | APKUtils.hideSoftInputFromWindow(SwipeBackActivity.this);
31 | }
32 |
33 | @Override
34 | public void onScrollOverThreshold() {
35 |
36 | }
37 | });
38 | }
39 |
40 | @Override
41 | protected void onPostCreate(Bundle savedInstanceState) {
42 | super.onPostCreate(savedInstanceState);
43 | mHelper.onPostCreate();
44 | }
45 |
46 | @Override
47 | public View findViewById(int id) {
48 | View v = super.findViewById(id);
49 | if (v == null && mHelper != null)
50 | return mHelper.findViewById(id);
51 | return v;
52 | }
53 |
54 | public void addSwipeListener(SwipeBackLayout.SwipeListener swipeListener) {
55 | getSwipeBackLayout().addSwipeListener(swipeListener);
56 | }
57 |
58 | public void setScrimColor(@ColorInt int color) {
59 | getSwipeBackLayout().setScrimColor(color);
60 | }
61 |
62 | @Override
63 | public SwipeBackLayout getSwipeBackLayout() {
64 | return mHelper.getSwipeBackLayout();
65 | }
66 |
67 | @Override
68 | public void setSwipeBackEnable(boolean enable) {
69 | getSwipeBackLayout().setEnableGesture(enable);
70 | }
71 |
72 | @Override
73 | public void scrollToFinishActivity() {
74 | Utils.convertActivityToTranslucent(this);
75 | getSwipeBackLayout().scrollToFinishActivity();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/swipeback/app/SwipeBackActivityBase.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.swipeback.app;
2 |
3 | import library.common.framework.ui.swipeback.SwipeBackLayout;
4 |
5 | /**
6 | * @author Yrom
7 | */
8 | public interface SwipeBackActivityBase {
9 | /**
10 | * @return the SwipeBackLayout associated with this activity.
11 | */
12 | public abstract SwipeBackLayout getSwipeBackLayout();
13 |
14 | public abstract void setSwipeBackEnable(boolean enable);
15 |
16 | /**
17 | * Scroll out contentView and finish the activity
18 | */
19 | public abstract void scrollToFinishActivity();
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/swipeback/app/SwipeBackActivityHelper.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.swipeback.app;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.graphics.drawable.ColorDrawable;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 |
9 | import library.common.R;
10 | import library.common.framework.ui.swipeback.SwipeBackLayout;
11 |
12 | /**
13 | * @author Yrom
14 | */
15 | public class SwipeBackActivityHelper {
16 | private Activity mActivity;
17 |
18 | private SwipeBackLayout mSwipeBackLayout;
19 |
20 | public SwipeBackActivityHelper(Activity activity) {
21 | mActivity = activity;
22 | }
23 |
24 | @SuppressWarnings("deprecation")
25 | public void onActivityCreate() {
26 | mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
27 | mActivity.getWindow().getDecorView().setBackgroundDrawable(null);
28 | mSwipeBackLayout = (SwipeBackLayout) View.inflate(mActivity, R.layout.com_swipeback_layout, null);
29 | }
30 |
31 | public void onPostCreate() {
32 | mSwipeBackLayout.attachToActivity(mActivity);
33 | }
34 |
35 | public View findViewById(int id) {
36 | if (mSwipeBackLayout != null) {
37 | return mSwipeBackLayout.findViewById(id);
38 | }
39 | return null;
40 | }
41 |
42 | public SwipeBackLayout getSwipeBackLayout() {
43 | return mSwipeBackLayout;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/swipeback/app/SwipeBackListenerActivityAdapter.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.swipeback.app;
2 |
3 | import android.app.Activity;
4 | import androidx.annotation.NonNull;
5 |
6 | import java.lang.ref.WeakReference;
7 |
8 | import library.common.framework.ui.swipeback.SwipeBackLayout;
9 | import library.common.framework.ui.swipeback.Utils;
10 |
11 | /**
12 | * Created by laysionqet on 2018/4/24.
13 | */
14 | public class SwipeBackListenerActivityAdapter implements SwipeBackLayout.SwipeListenerEx {
15 | private final WeakReference mActivity;
16 |
17 | public SwipeBackListenerActivityAdapter(@NonNull Activity activity) {
18 | mActivity = new WeakReference<>(activity);
19 | }
20 |
21 | @Override
22 | public void onScrollStateChange(int state, float scrollPercent) {
23 |
24 | }
25 |
26 | @Override
27 | public void onEdgeTouch(int edgeFlag) {
28 | Activity activity = mActivity.get();
29 | if (null != activity) {
30 | Utils.convertActivityToTranslucent(activity);
31 | }
32 | }
33 |
34 | @Override
35 | public void onScrollOverThreshold() {
36 |
37 | }
38 |
39 | @Override
40 | public void onContentViewSwipedBack() {
41 | Activity activity = mActivity.get();
42 | if (null != activity && !activity.isFinishing()) {
43 | activity.finish();
44 | activity.overridePendingTransition(0, 0);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/AbstractLoadHelper.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 | import android.content.res.Resources;
6 | import androidx.annotation.DrawableRes;
7 | import androidx.annotation.LayoutRes;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 |
11 | /**
12 | * 加载、错误、空数据、Toast、模态(非模态)对话框辅助类
13 | *
14 | * @author zhuhf
15 | * @version [AndroidLibrary, 2018-04-21]
16 | */
17 | public abstract class AbstractLoadHelper {
18 | private ViewSwitcher vs;
19 | LayoutInflater inflater;
20 | protected Context mContext;
21 |
22 | /**
23 | * @param view 内容布局
24 | */
25 | public AbstractLoadHelper(View view) {
26 | vs = new ViewSwitcher(view);
27 | inflater = LayoutInflater.from(view.getContext());
28 | mContext = view.getContext();
29 | }
30 |
31 | /**
32 | * 加载视图
33 | *
34 | * @param loadText
35 | * @param loadRes
36 | * @param bgRes
37 | * @return
38 | */
39 | public abstract View loadingView(String loadText, @DrawableRes int loadRes, @DrawableRes int bgRes);
40 |
41 | /**
42 | * 错误视图
43 | *
44 | * @param errorText
45 | * @param errorRes
46 | * @param showButton
47 | * @param buttonText
48 | * @param bgRes
49 | * @param onClickListener
50 | * @return
51 | */
52 | public abstract View errorView(String errorText, @DrawableRes int errorRes, boolean showButton, String buttonText,
53 | @DrawableRes int bgRes, View.OnClickListener onClickListener);
54 |
55 | /**
56 | * 空视图
57 | *
58 | * @param emptyText
59 | * @param emptyRes
60 | * @param buttonText
61 | * @param bgResId
62 | * @param onClickListener
63 | * @return
64 | */
65 | public abstract View emptyView(String emptyText, @DrawableRes int emptyRes, String buttonText,
66 | @DrawableRes int bgResId, View.OnClickListener onClickListener);
67 |
68 | /**
69 | * 显示默认 View
70 | */
71 | public void hide() {
72 | vs.reset();
73 | }
74 |
75 | /**
76 | * 显示指定的 View
77 | *
78 | * @param view
79 | */
80 | public void show(View view) {
81 | vs.show(view);
82 | }
83 |
84 | public View inflate(@LayoutRes int resource) {
85 | return inflater.inflate(resource, null);
86 | }
87 |
88 | public Resources getResources() {
89 | return mContext.getResources();
90 | }
91 |
92 | /**
93 | * 显示加载框
94 | *
95 | * @param message
96 | * @param cancelable
97 | */
98 | public abstract void showProgress(String message, boolean cancelable);
99 |
100 | /**
101 | * 显示加载框
102 | *
103 | * @param message
104 | * @param cancelable
105 | * @param cancelListener
106 | */
107 | public abstract void showProgress(String message, boolean cancelable, DialogInterface.OnCancelListener cancelListener);
108 |
109 | /**
110 | * 隐藏加载框
111 | */
112 | public abstract void hideProgress();
113 |
114 | /**
115 | * Toast
116 | *
117 | * @param message
118 | */
119 | public abstract void showToast(CharSequence message);
120 | }
121 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/CircleImageView.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | /**
7 | * 圆形 ImageView
8 | *
9 | * @author zhuhf
10 | * @version 2020/9/15
11 | */
12 | public class CircleImageView extends RoundImageView {
13 | public CircleImageView(Context context) {
14 | this(context, null);
15 | }
16 |
17 | public CircleImageView(Context context, AttributeSet attrs) {
18 | this(context, attrs, -1);
19 | }
20 |
21 | public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
22 | super(context, attrs, defStyle);
23 | setDrawCircle();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/DashLine.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.DashPathEffect;
9 | import android.graphics.Paint;
10 | import androidx.annotation.Nullable;
11 | import android.util.AttributeSet;
12 | import android.view.View;
13 |
14 | import library.common.R;
15 | import library.common.util.APKUtils;
16 |
17 | /**
18 | * 虚线
19 | *
20 | * @author zhuhf
21 | * @version [AndroidLibrary, 2018-03-09]
22 | */
23 | public class DashLine extends View {
24 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
25 | float strokeWidth;
26 | boolean isVertical;
27 |
28 | public DashLine(Context context, @Nullable AttributeSet attrs) {
29 | this(context, attrs, -1);
30 | }
31 |
32 | public DashLine(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
33 | super(context, attrs, defStyleAttr);
34 | // 禁止硬件加速
35 | setLayerType(LAYER_TYPE_SOFTWARE, null);
36 |
37 | @SuppressLint("CustomViewStyleable") TypedArray a = context.obtainStyledAttributes(attrs,
38 | R.styleable.com_DashLine);
39 | isVertical = a.getBoolean(R.styleable.com_DashLine_com_vertical, false);
40 | strokeWidth = a.getDimensionPixelSize(R.styleable.com_DashLine_com_strokeWidth, APKUtils.dip2px(context, 2));
41 | paint.setColor(a.getColor(R.styleable.com_DashLine_com_color, Color.parseColor("#dddddd")));
42 | paint.setStyle(Paint.Style.STROKE);
43 | paint.setStrokeWidth(strokeWidth);
44 | paint.setPathEffect(new DashPathEffect(new float[]{
45 | a.getDimensionPixelSize(R.styleable.com_DashLine_com_dashWidth, APKUtils.dip2px(context, 3)),
46 | a.getDimensionPixelSize(R.styleable.com_DashLine_com_dashGap, APKUtils.dip2px(context, 1))}, 0));
47 |
48 | a.recycle();
49 | }
50 |
51 | @Override
52 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
53 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
54 | if (isVertical) {
55 | setMeasuredDimension((int) strokeWidth, getMeasuredHeight());
56 | } else {
57 | setMeasuredDimension(getMeasuredWidth(), (int) strokeWidth);
58 | }
59 | }
60 |
61 | @Override
62 | protected void onDraw(Canvas canvas) {
63 | super.onDraw(canvas);
64 | if (isVertical) {
65 | canvas.drawLine(0, 0, 0, getMeasuredHeight(), paint);
66 | } else {
67 | canvas.drawLine(0, 0, getMeasuredWidth(), 0, paint);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/ListenableScrollView.kt:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.core.widget.NestedScrollView
7 |
8 | /**
9 | * 可监听 X 或 Y 方向滚动比例
10 | *
11 | * @author hyvenzhu
12 | * @version 2022/8/19
13 | */
14 | class ListenableScrollView(context: Context, attributeSet: AttributeSet?) :
15 | NestedScrollView(context, attributeSet) {
16 | constructor(context: Context) : this(context, null)
17 |
18 | /**
19 | * X 或 Y 方向滚动比例监听器
20 | */
21 | var scrollListener: ((scrollXPercent: Float, scrollYPercent: Float) -> Unit)? = null
22 |
23 | /**
24 | * 滚动比例参照 View
25 | */
26 | lateinit var refView: View
27 |
28 | override fun onScrollChanged(scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) {
29 | super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY)
30 | scrollListener?.invoke((scrollX.toFloat() / refView.width).coerceAtMost(1f), (scrollY.toFloat() / refView.height).coerceAtMost(1f))
31 | }
32 | }
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/NestedScrollWebView.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import androidx.core.view.MotionEventCompat;
6 | import androidx.core.view.NestedScrollingChild;
7 | import androidx.core.view.NestedScrollingChildHelper;
8 | import androidx.core.view.ViewCompat;
9 | import android.util.AttributeSet;
10 | import android.view.MotionEvent;
11 | import android.webkit.WebView;
12 |
13 | /**
14 | * 可 Nested 滚动的 WebView
15 | * @author hiphonezhu@gmail.com
16 | * @version [AndroidLibrary, 2018-3-6]
17 | */
18 | public class NestedScrollWebView extends WebView implements NestedScrollingChild {
19 |
20 | public static final String TAG = NestedScrollWebView.class.getSimpleName();
21 |
22 | private int mLastMotionY;
23 |
24 | private final int[] mScrollOffset = new int[2];
25 | private final int[] mScrollConsumed = new int[2];
26 |
27 | private int mNestedYOffset;
28 |
29 | private NestedScrollingChildHelper mChildHelper;
30 |
31 | public NestedScrollWebView(Context context) {
32 | super(context);
33 | init();
34 | }
35 |
36 | public NestedScrollWebView(Context context, AttributeSet attrs) {
37 | super(context, attrs);
38 | init();
39 | }
40 |
41 | public NestedScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
42 | super(context, attrs, defStyleAttr);
43 | init();
44 | }
45 |
46 | private void init() {
47 | mChildHelper = new NestedScrollingChildHelper(this);
48 | setNestedScrollingEnabled(true);
49 | }
50 |
51 | @SuppressLint("ClickableViewAccessibility")
52 | @Override
53 | public boolean onTouchEvent(MotionEvent event) {
54 | boolean result = false;
55 |
56 | MotionEvent trackedEvent = MotionEvent.obtain(event);
57 |
58 | final int action = MotionEventCompat.getActionMasked(event);
59 |
60 | if (action == MotionEvent.ACTION_DOWN) {
61 | mNestedYOffset = 0;
62 | }
63 |
64 | int y = (int) event.getY();
65 |
66 | event.offsetLocation(0, mNestedYOffset);
67 |
68 | switch (action) {
69 | case MotionEvent.ACTION_DOWN:
70 | mLastMotionY = y;
71 | startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
72 | result = super.onTouchEvent(event);
73 | break;
74 | case MotionEvent.ACTION_MOVE:
75 | int deltaY = mLastMotionY - y;
76 |
77 | if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
78 | deltaY -= mScrollConsumed[1];
79 | trackedEvent.offsetLocation(0, mScrollOffset[1]);
80 | mNestedYOffset += mScrollOffset[1];
81 | }
82 |
83 | int oldY = getScrollY();
84 | mLastMotionY = y - mScrollOffset[1];
85 | if (deltaY < 0) {
86 | int newScrollY = Math.max(0, oldY + deltaY);
87 | deltaY -= newScrollY - oldY;
88 | if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
89 | mLastMotionY -= mScrollOffset[1];
90 | trackedEvent.offsetLocation(0, mScrollOffset[1]);
91 | mNestedYOffset += mScrollOffset[1];
92 | }
93 | }
94 |
95 | result = super.onTouchEvent(trackedEvent);
96 | trackedEvent.recycle();
97 | break;
98 | case MotionEvent.ACTION_POINTER_DOWN:
99 | case MotionEvent.ACTION_UP:
100 | case MotionEvent.ACTION_CANCEL:
101 | stopNestedScroll();
102 | result = super.onTouchEvent(event);
103 | break;
104 | }
105 | return result;
106 | }
107 |
108 | // NestedScrollingChild
109 |
110 | @Override
111 | public void setNestedScrollingEnabled(boolean enabled) {
112 | mChildHelper.setNestedScrollingEnabled(enabled);
113 | }
114 |
115 | @Override
116 | public boolean isNestedScrollingEnabled() {
117 | return mChildHelper.isNestedScrollingEnabled();
118 | }
119 |
120 | @Override
121 | public boolean startNestedScroll(int axes) {
122 | return mChildHelper.startNestedScroll(axes);
123 | }
124 |
125 | @Override
126 | public void stopNestedScroll() {
127 | mChildHelper.stopNestedScroll();
128 | }
129 |
130 | @Override
131 | public boolean hasNestedScrollingParent() {
132 | return mChildHelper.hasNestedScrollingParent();
133 | }
134 |
135 | @Override
136 | public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
137 | return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
138 | }
139 |
140 | @Override
141 | public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
142 | return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
143 | }
144 |
145 | @Override
146 | public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
147 | return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
148 | }
149 |
150 | @Override
151 | public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
152 | return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/ToastHelper.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.view.Gravity;
7 | import android.widget.Toast;
8 |
9 | import androidx.annotation.StringRes;
10 |
11 | import java.lang.reflect.Field;
12 |
13 |
14 | /**
15 | * Toast 工具类
16 | *
17 | * @author zhuhf
18 | * @version [AndroidLibrary-5.10, 2018-05-13]
19 | */
20 | public class ToastHelper {
21 | private static Field sField_TN;
22 | private static Field sField_TN_Handler;
23 | private static android.widget.Toast mToast;
24 |
25 | static {
26 | try {
27 | sField_TN = Toast.class.getDeclaredField("mTN");
28 | sField_TN.setAccessible(true);
29 | sField_TN_Handler = sField_TN.getType().getDeclaredField("mHandler");
30 | sField_TN_Handler.setAccessible(true);
31 | } catch (Exception e) {
32 | }
33 | }
34 |
35 | /**
36 | * Toast
37 | *
38 | * @param message
39 | */
40 | public static void showToast(Context context, CharSequence message) {
41 | if (mToast == null) {
42 | mToast = Toast.makeText(context.getApplicationContext(),
43 | message,
44 | Toast.LENGTH_SHORT);
45 | mToast.setGravity(Gravity.CENTER, 0, 0);
46 | } else {
47 | mToast.setText(message);
48 | }
49 | hook(mToast);
50 | mToast.show();
51 | }
52 |
53 | public static void showToast(Context context, @StringRes int message) {
54 | showToast(context, context.getString(message));
55 | }
56 |
57 | private static void hook(Toast toast) {
58 | try {
59 | Object tn = sField_TN.get(toast);
60 | Handler preHandler = (Handler) sField_TN_Handler.get(tn);
61 | sField_TN_Handler.set(tn, new SafelyHandlerWrapper(preHandler));
62 | } catch (Exception e) {
63 | }
64 | }
65 |
66 | private static class SafelyHandlerWrapper extends Handler {
67 | private Handler impl;
68 |
69 | public SafelyHandlerWrapper(Handler impl) {
70 | this.impl = impl;
71 | }
72 |
73 | @Override
74 | public void dispatchMessage(Message msg) {
75 | try {
76 | super.dispatchMessage(msg);
77 | } catch (Exception e) {
78 | }
79 | }
80 |
81 | @Override
82 | public void handleMessage(Message msg) {
83 | impl.handleMessage(msg);//需要委托给原Handler执行
84 | }
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/ViewExtentions.kt:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget
2 |
3 | import android.widget.TextView
4 | import androidx.core.widget.doAfterTextChanged
5 |
6 | /**
7 | * [TextView] 有输入内容时加粗;反之,不加粗。
8 | * 不要再 xml 设置 android:textStyle="bold",否则无效
9 | */
10 | fun TextView.fakeBoldByInput() {
11 | doAfterTextChanged {
12 | paint.isFakeBoldText = it.toString().isNotEmpty()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/framework/ui/widget/ViewSwitcher.java:
--------------------------------------------------------------------------------
1 | package library.common.framework.ui.widget;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | /**
8 | * 两个 View 切换显示
9 | *
10 | * @author zhuhf
11 | * @version [AndroidLibrary, 2018-04-12]
12 | */
13 | public class ViewSwitcher {
14 | /**
15 | * 原内容View参数
16 | */
17 | private View mView;
18 | private ViewGroup parentView;
19 | private int viewIndex;
20 | private ViewGroup.LayoutParams params;
21 | int height;
22 |
23 | /**
24 | * 加载布局
25 | */
26 | View loadingView;
27 |
28 | /**
29 | * @param view 初始化要显示的 View
30 | */
31 | public ViewSwitcher(View view) {
32 | super();
33 | mView = view;
34 | init();
35 | }
36 |
37 | /**
38 | * 显示特定的 View,替换 mView
39 | *
40 | * @param view
41 | */
42 | public void show(View view) {
43 | loadingView = view;
44 | if (parentView == null) {
45 | init();
46 | }
47 | if (view != mView) {
48 | ViewGroup parent = (ViewGroup) view.getParent();
49 | if (parent != null) {
50 | parent.removeView(view);
51 | }
52 | // 显示其他视图
53 | mView.setVisibility(View.GONE);
54 | if (parentView.getChildAt(viewIndex) != mView) {
55 | parentView.removeViewAt(viewIndex);
56 | }
57 | parentView.addView(view, viewIndex, params);
58 | } else {
59 | // 显示原视图
60 | mView.setVisibility(View.VISIBLE);
61 | if (parentView.getChildAt(viewIndex) != mView) {
62 | parentView.removeViewAt(viewIndex);
63 | }
64 | }
65 | }
66 |
67 | public void show(int layoutId) {
68 | show(inflate(layoutId));
69 | }
70 |
71 | /**
72 | * 显示 mView
73 | */
74 | public void reset() {
75 | if (loadingView != mView) {
76 | show(mView);
77 | }
78 | }
79 |
80 | public View inflate(int layoutId) {
81 | return LayoutInflater.from(mView.getContext()).inflate(layoutId, null);
82 | }
83 |
84 | /**
85 | * 查找 mView 的 Index
86 | */
87 | private void init() {
88 | params = mView.getLayoutParams();
89 | height = params.height;
90 | if (mView.getParent() != null) {
91 | parentView = (ViewGroup) mView.getParent();
92 | } else {
93 | parentView = mView.getRootView().findViewById(
94 | android.R.id.content);
95 | }
96 | int count = parentView.getChildCount();
97 | for (int index = 0; index < count; index++) {
98 | if (mView == parentView.getChildAt(index)) {
99 | viewIndex = index;
100 | break;
101 | }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/AndroidBug5497Workaround.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | import android.graphics.Rect;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.view.ViewTreeObserver;
7 |
8 | /**
9 | * 结局 沉浸式和 adjustResize 冲突
10 | * 使用方法:AndroidBug5497Workaround.assistActivity(findViewById(android.R.id.content));
11 | *
12 | * @author zhuhf
13 | * @version 2019-06-19
14 | */
15 | public class AndroidBug5497Workaround {
16 | public static void assistActivity(View content) {
17 | new AndroidBug5497Workaround(content);
18 | }
19 |
20 | private View mChildOfContent;
21 | private int usableHeightPrevious;
22 | private ViewGroup.LayoutParams frameLayoutParams;
23 |
24 | private AndroidBug5497Workaround(View content) {
25 | if (content != null) {
26 | mChildOfContent = content;
27 | mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
28 | @Override
29 | public void onGlobalLayout() {
30 | possiblyResizeChildOfContent();
31 | }
32 | });
33 | frameLayoutParams = mChildOfContent.getLayoutParams();
34 | }
35 | }
36 |
37 | private void possiblyResizeChildOfContent() {
38 | int usableHeightNow = computeUsableHeight();
39 | if (usableHeightNow != usableHeightPrevious) {
40 | // 如果两次高度不一致
41 | // 将计算的可视高度设置成视图的高度
42 | frameLayoutParams.height = usableHeightNow;
43 | mChildOfContent.requestLayout();
44 | usableHeightPrevious = usableHeightNow;
45 | }
46 | }
47 |
48 | private int computeUsableHeight() {
49 | // 计算视图可视高度
50 | Rect r = new Rect();
51 | mChildOfContent.getWindowVisibleDisplayFrame(r);
52 | return (r.bottom);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/CacheDiskLogStrategy.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.HandlerThread;
6 | import android.os.Looper;
7 | import android.os.Message;
8 |
9 | import androidx.annotation.NonNull;
10 |
11 | import com.orhanobut.logger.LogStrategy;
12 |
13 | import java.io.File;
14 | import java.io.FileWriter;
15 | import java.io.IOException;
16 |
17 | /**
18 | * 日志文件存储在应用缓存目录
19 | *
20 | * @author hyvenzhu
21 | * @version 2023/9/6
22 | */
23 | public class CacheDiskLogStrategy implements LogStrategy {
24 |
25 | private static final int MAX_BYTES = 500 * 1024; // 500K averages to a 4000 lines per file
26 |
27 | private final Handler handler;
28 |
29 | public CacheDiskLogStrategy(Context context) {
30 | String diskPath = context.getExternalCacheDir().getAbsolutePath();
31 | String folder = diskPath + File.separatorChar + "logger";
32 |
33 | HandlerThread ht = new HandlerThread("AndroidCacheFileLogger." + folder);
34 | ht.start();
35 | this.handler = new WriteHandler(ht.getLooper(), folder, MAX_BYTES);
36 | }
37 |
38 | @Override
39 | public void log(int priority, String tag, String message) {
40 | handler.sendMessage(handler.obtainMessage(priority, message));
41 | }
42 |
43 | static class WriteHandler extends Handler {
44 |
45 | @NonNull private final String folder;
46 | private final int maxFileSize;
47 |
48 | WriteHandler(@NonNull Looper looper, @NonNull String folder, int maxFileSize) {
49 | super(looper);
50 | this.folder = folder;
51 | this.maxFileSize = maxFileSize;
52 | }
53 |
54 | @SuppressWarnings("checkstyle:emptyblock")
55 | @Override public void handleMessage(@NonNull Message msg) {
56 | String content = (String) msg.obj;
57 |
58 | FileWriter fileWriter = null;
59 | File logFile = getLogFile(folder, "logs");
60 |
61 | try {
62 | fileWriter = new FileWriter(logFile, true);
63 |
64 | writeLog(fileWriter, content);
65 |
66 | fileWriter.flush();
67 | fileWriter.close();
68 | } catch (IOException e) {
69 | if (fileWriter != null) {
70 | try {
71 | fileWriter.flush();
72 | fileWriter.close();
73 | } catch (IOException e1) { /* fail silently */ }
74 | }
75 | }
76 | }
77 |
78 | /**
79 | * This is always called on a single background thread.
80 | * Implementing classes must ONLY write to the fileWriter and nothing more.
81 | * The abstract class takes care of everything else including close the stream and catching IOException
82 | *
83 | * @param fileWriter an instance of FileWriter already initialised to the correct file
84 | */
85 | private void writeLog(@NonNull FileWriter fileWriter, @NonNull String content) throws IOException {
86 | fileWriter.append(content);
87 | }
88 |
89 | private File getLogFile(@NonNull String folderName, @NonNull String fileName) {
90 | File folder = new File(folderName);
91 | if (!folder.exists()) {
92 | //TODO: What if folder is not created, what happens then?
93 | folder.mkdirs();
94 | }
95 |
96 | int newFileCount = 0;
97 | File newFile;
98 | File existingFile = null;
99 |
100 | newFile = new File(folder, String.format("%s_%s.csv", fileName, newFileCount));
101 | while (newFile.exists()) {
102 | existingFile = newFile;
103 | newFileCount++;
104 | newFile = new File(folder, String.format("%s_%s.csv", fileName, newFileCount));
105 | }
106 |
107 | if (existingFile != null) {
108 | if (existingFile.length() >= maxFileSize) {
109 | return newFile;
110 | }
111 | return existingFile;
112 | }
113 |
114 | return newFile;
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/Callback.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | /**
4 | * @author zhuhf
5 | * @version [AndroidLibrary, 2018-03-14]
6 | */
7 | public interface Callback {
8 | /**
9 | * call the observer
10 | *
11 | * @param data
12 | */
13 | void call(T data);
14 | }
15 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/IntentUtils.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import androidx.fragment.app.Fragment;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Intent跳转工具类
13 | *
14 | * @author hiphonezhu@gmail.com
15 | * @version [AndroidLibrary, 2018-3-6]
16 | */
17 |
18 | public class IntentUtils {
19 |
20 | public static void startActivity(Activity activity, Class destClass) {
21 | startActivity(activity, destClass, null);
22 | }
23 |
24 | public static void startActivity(Activity activity, Class destClass, Bundle extras) {
25 | Intent intent = new Intent(activity, destClass);
26 | if (extras != null) {
27 | intent.putExtras(extras);
28 | }
29 | startActivity(intent, activity);
30 | }
31 |
32 | public static void startActivity(Intent intent, Activity activity) {
33 | activity.startActivity(intent);
34 | }
35 |
36 | public static void startActivityForResult(Activity activity, Class destClass, int requestCode) {
37 | startActivityForResult(activity, destClass, requestCode, null);
38 | }
39 |
40 | public static void startActivityForResult(Activity activity, Class destClass, int requestCode, Bundle extras) {
41 | Intent intent = new Intent(activity, destClass);
42 | if (extras != null) {
43 | intent.putExtras(extras);
44 | }
45 | startActivityForResult(intent, activity, requestCode);
46 | }
47 |
48 | public static void startActivityForResult(Intent intent, Activity activity, int requestCode) {
49 | activity.startActivityForResult(intent, requestCode);
50 | }
51 |
52 | public static void startActivityForResult(Fragment fragment, Class destClass, int requestCode) {
53 | startActivityForResult(fragment, destClass, requestCode, null);
54 | }
55 |
56 | public static void startActivityForResult(Fragment fragment, Class destClass, int requestCode, Bundle extras) {
57 | Intent intent = new Intent(fragment.getActivity(), destClass);
58 | if (extras != null) {
59 | intent.putExtras(extras);
60 | }
61 | startActivityForResult(intent, fragment, requestCode);
62 | }
63 |
64 | public static void startActivityForResult(Intent intent, Fragment fragment, int requestCode) {
65 | fragment.startActivityForResult(intent, requestCode);
66 | }
67 |
68 | public static void startSingleTopActivity(Activity activity, Class destClass) {
69 | startSingleTopActivity(activity, destClass, null);
70 | }
71 |
72 | public static void startSingleTopActivity(Activity activity, Class destClass, Bundle extras) {
73 | Intent intent = new Intent(activity, destClass);
74 | if (extras != null) {
75 | intent.putExtras(extras);
76 | }
77 | intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
78 | activity.startActivity(intent);
79 | }
80 |
81 | public static void startSingleTaskActivity(Context context, Class destClass) {
82 | startSingleTaskActivity(context, destClass, null);
83 | }
84 |
85 | public static void startSingleTaskActivity(Context context, Class destClass, Bundle extras) {
86 | Intent intent = new Intent(context, destClass);
87 | if (extras != null) {
88 | intent.putExtras(extras);
89 | }
90 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
91 | context.startActivity(intent);
92 | }
93 |
94 | public static boolean isIntentAvailable(Context context, Intent intent) {
95 | List resolves = context.getPackageManager().queryIntentActivities(intent, 0);
96 | return resolves.size() > 0;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/LogUtils.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | import android.content.Context;
4 |
5 | import com.orhanobut.logger.AndroidLogAdapter;
6 | import com.orhanobut.logger.CsvFormatStrategy;
7 | import com.orhanobut.logger.DiskLogAdapter;
8 | import com.orhanobut.logger.Logger;
9 |
10 | /**
11 | * Log 日志类工具
12 | * 详见:https://github.com/orhanobut/logger
13 | *
14 | * @author hiphonezhu@gmail.com
15 | * @version [AndroidLibrary, 2018-3-6]
16 | */
17 | public class LogUtils {
18 |
19 | private static final int FILE = 8;
20 |
21 | static {
22 | Logger.addLogAdapter(new AndroidLogAdapter() {
23 | @Override
24 | public boolean isLoggable(int priority, String tag) {
25 | return APKUtils.isDebug();
26 | }
27 | });
28 | }
29 |
30 | public static void tag(String tag) {
31 | Logger.t(tag);
32 | }
33 |
34 | public static void addDiskLogAdapter(Context context) {
35 | Logger.addLogAdapter(new DiskLogAdapter(CsvFormatStrategy.newBuilder().logStrategy(new CacheDiskLogStrategy(context)).build()) {
36 | @Override
37 | public boolean isLoggable(int priority, String tag) {
38 | return priority == FILE;
39 | }
40 | });
41 | }
42 |
43 | public static void toFile(String tag, String message) {
44 | Logger.log(FILE, tag, message, null);
45 | }
46 |
47 | public static void toFile(String message) {
48 | Logger.log(FILE, "toFile", message, null);
49 | }
50 |
51 | public static void d(Object object) {
52 | Logger.d(object);
53 | }
54 |
55 | public static void d(String message, Object... args) {
56 | Logger.d(message, args);
57 | }
58 |
59 | public static void e(String message, Object... args) {
60 | Logger.e(message, args);
61 | }
62 |
63 | public static void e(Throwable throwable) {
64 | Logger.e(throwable, "", "");
65 | }
66 |
67 | public static void w(String message, Object... args) {
68 | Logger.w(message, args);
69 | }
70 |
71 | public static void v(String message, Object... args) {
72 | Logger.v(message, args);
73 | }
74 |
75 | public static void i(String message, Object... args) {
76 | Logger.i(message, args);
77 | }
78 |
79 | public static void wtf(String message, Object... args) {
80 | Logger.wtf(message, args);
81 | }
82 |
83 | public static void json(String json) {
84 | Logger.json(json);
85 | }
86 |
87 | public static void xml(String xml) {
88 | Logger.xml(xml);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/NoDoubleClickListener.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | import android.view.View;
4 |
5 | import java.util.Calendar;
6 |
7 | /**
8 | * @author zhuhf
9 | * @version [AndroidLibrary, 2018/10/25]
10 | */
11 | public abstract class NoDoubleClickListener implements View.OnClickListener {
12 | public static final int MIN_CLICK_DELAY_TIME = 500;
13 | private long lastClickTime = 0;
14 |
15 | @Override
16 | public void onClick(View v) {
17 | long currentTime = Calendar.getInstance().getTimeInMillis();
18 | if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
19 | lastClickTime = currentTime;
20 | onNoDoubleClick(v);
21 | }
22 | }
23 |
24 | protected abstract void onNoDoubleClick(View v);
25 | }
26 |
--------------------------------------------------------------------------------
/library_android/src/main/java/library/common/util/StatusBarUtils.java:
--------------------------------------------------------------------------------
1 | package library.common.util;
2 |
3 | import android.app.Activity;
4 | import androidx.annotation.ColorInt;
5 | import androidx.fragment.app.Fragment;
6 | import android.view.View;
7 |
8 | import com.jaeger.library.StatusBarUtil;
9 |
10 | /**
11 | * 状态栏工具类
12 | *
13 | * @author hiphonezhu@gmail.com
14 | * @version [AndroidLibrary, 2018-11-21]
15 | */
16 | public class StatusBarUtils {
17 |
18 | public static void setTranslucent(Activity activity, View offsetView) {
19 | StatusBarUtil.setTranslucentForImageView(activity, 0, offsetView);
20 | }
21 |
22 | public static void setTranslucent(Fragment fragment, View offsetView) {
23 | StatusBarUtil.setTranslucentForImageViewInFragment(fragment.getActivity(), 0, offsetView);
24 | }
25 |
26 | public static void setColor(Activity activity, @ColorInt int color) {
27 | StatusBarUtil.setColor(activity, color, 0);
28 | }
29 |
30 | public static void setLightMode(Activity activity) {
31 | StatusBarUtil.setLightMode(activity);
32 | }
33 |
34 | public static void setDarkMode(Activity activity) {
35 | StatusBarUtil.setDarkMode(activity);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/library_android/src/main/res/drawable-xxhdpi/com_shadow_bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyvenzhu/AndroidLibrary/4f84aa2ad71e9ba36eca24d68b3eab19d5b866ab/library_android/src/main/res/drawable-xxhdpi/com_shadow_bottom.png
--------------------------------------------------------------------------------
/library_android/src/main/res/drawable-xxhdpi/com_shadow_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyvenzhu/AndroidLibrary/4f84aa2ad71e9ba36eca24d68b3eab19d5b866ab/library_android/src/main/res/drawable-xxhdpi/com_shadow_left.png
--------------------------------------------------------------------------------
/library_android/src/main/res/drawable-xxhdpi/com_shadow_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyvenzhu/AndroidLibrary/4f84aa2ad71e9ba36eca24d68b3eab19d5b866ab/library_android/src/main/res/drawable-xxhdpi/com_shadow_right.png
--------------------------------------------------------------------------------
/library_android/src/main/res/layout/com_activity_common.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/library_android/src/main/res/layout/com_swipeback_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/library_android/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/library_android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #EDEDED
4 | #333333
5 | #ffffff
6 |
--------------------------------------------------------------------------------
/library_android/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library_android/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 正在加载, 请稍候...
4 | 权限申请
5 | 需要%1$s的权限,但此权限已被禁止,您可以到设置中更改。
6 | 去设置
7 | 重试
8 | 正在加载中...
9 | .....<页面加载失败]]>
10 | 暂无数据哦
11 | 重新加载
12 |
--------------------------------------------------------------------------------
/library_android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
13 |
17 |
18 |
19 |
22 |
23 |
24 |
26 |
27 |
33 |
34 |
--------------------------------------------------------------------------------
/library_android/src/main/res/xml/com_file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/library_android/src/main/res/xml/com_network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library_mqtt/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/library_mqtt/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'library.mqtt'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | minSdk 21
12 | targetSdk 33
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | consumerProguardFiles "consumer-rules.pro"
16 | }
17 |
18 | lintOptions {
19 | abortOnError false
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 | kotlinOptions {
33 | jvmTarget = '1.8'
34 | }
35 | }
36 |
37 | dependencies {
38 | api("org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0")
39 | api("org.eclipse.paho:org.eclipse.paho.android.service:1.1.1")
40 |
41 | implementation 'androidx.core:core-ktx:1.8.0'
42 | implementation 'androidx.appcompat:appcompat:1.4.1'
43 | implementation 'com.google.android.material:material:1.5.0'
44 | testImplementation 'junit:junit:4.13.2'
45 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
46 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
47 | }
--------------------------------------------------------------------------------
/library_mqtt/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyvenzhu/AndroidLibrary/4f84aa2ad71e9ba36eca24d68b3eab19d5b866ab/library_mqtt/consumer-rules.pro
--------------------------------------------------------------------------------
/library_mqtt/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
--------------------------------------------------------------------------------
/library_mqtt/src/androidTest/java/library/mqtt/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package library.mqtt
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("library.mqtt.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/library_mqtt/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/library_mqtt/src/main/java/library/mqtt/MqttConfig.kt:
--------------------------------------------------------------------------------
1 | package library.mqtt
2 |
3 | /**
4 | * Mqtt 配置项
5 | *
6 | * @author hyvenzhu
7 | * @version 2022/2/9
8 | */
9 | class MqttConfig private constructor(val configParams: ConfigParams) {
10 |
11 | companion object {
12 |
13 | @Volatile
14 | private var INSTANCE: MqttConfig? = null
15 |
16 | fun init(configParams: ConfigParams) {
17 | INSTANCE ?: synchronized(this) {
18 | INSTANCE ?: MqttConfig(configParams).also { INSTANCE = it }
19 | }
20 | }
21 |
22 | fun get(): MqttConfig =
23 | INSTANCE ?: throw RuntimeException("MqttConfig must call init first!!!")
24 | }
25 | }
26 |
27 | class ConfigParams(
28 | val serviceURI: String,
29 | val userName: String,
30 | val password: String,
31 | val connectTimeout: Int = 10,
32 | val keepAliveInterval: Int = 20
33 | )
--------------------------------------------------------------------------------
/library_mqtt/src/main/java/library/mqtt/MqttStatusEnum.kt:
--------------------------------------------------------------------------------
1 | package library.mqtt
2 |
3 | /**
4 | * MQTT 连接状态
5 | *
6 | * @author hyvenzhu
7 | * @version 2024/1/22
8 | */
9 | enum class MqttStatusEnum {
10 |
11 | CONNECTING,
12 |
13 | CONNECTED,
14 |
15 | DISCONNECTED,
16 | }
--------------------------------------------------------------------------------
/library_mqtt/src/test/java/library/mqtt/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package library.mqtt
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Thu Feb 29 12:41:51 CST 2024
8 | sdk.dir=/home/hyvenzhu/Android/Sdk
9 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':demo'
2 | include ':library_android'
3 | include ':library_mqtt'
4 |
--------------------------------------------------------------------------------