diff --git a/app-base/build.gradle b/app-base/build.gradle index cd18aa4..a5b1d6d 100644 --- a/app-base/build.gradle +++ b/app-base/build.gradle @@ -28,4 +28,8 @@ dependencies { api project(path: ':cpage') api project(path: ':xui_lib') + api project(path: ':app-util-sub') + api project(path: ':easypermissionlib') + + } diff --git a/app-base/src/main/java/com/cain/base/base/BaseActivity.java b/app-base/src/main/java/com/cain/base/base/BaseActivity.java index e275e70..7e6a5ca 100644 --- a/app-base/src/main/java/com/cain/base/base/BaseActivity.java +++ b/app-base/src/main/java/com/cain/base/base/BaseActivity.java @@ -2,9 +2,12 @@ import android.os.Bundle; +import androidx.annotation.NonNull; + import com.cain.cpage.base.CPageActivity; import com.cain.cpage.base.CPageFragment; import com.cain.cpage.core.CoreSwitchBean; +import com.zyq.easypermission.EasyPermissionHelper; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -99,4 +102,11 @@ protected void onRelease() { super.onRelease(); } + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + EasyPermissionHelper.getInstance().onRequestPermissionsResult(requestCode, permissions, grantResults, this); + + } } diff --git a/app-base/src/main/java/com/cain/base/base/BaseFragment.java b/app-base/src/main/java/com/cain/base/base/BaseFragment.java index 46ea026..aa64c3b 100644 --- a/app-base/src/main/java/com/cain/base/base/BaseFragment.java +++ b/app-base/src/main/java/com/cain/base/base/BaseFragment.java @@ -268,4 +268,6 @@ public androidx.fragment.app.Fragment openPageForResul .setRequestCode(requestCode) .open(this); } + + } diff --git a/app-base/src/main/java/com/cain/base/base/logs/ILogger.java b/app-base/src/main/java/com/cain/base/base/logs/ILogger.java new file mode 100644 index 0000000..ab3ceee --- /dev/null +++ b/app-base/src/main/java/com/cain/base/base/logs/ILogger.java @@ -0,0 +1,22 @@ + +package com.cain.base.base.logs; + +/** + * 简易的日志记录接口 + * + * @author xuexiang + * @since 2019年1月14日 下午10:15 + */ +public interface ILogger { + + /** + * 打印信息 + * + * @param priority 优先级 + * @param tag 标签 + * @param message 信息 + * @param t 出错信息 + */ + void log(int priority, String tag, String message, Throwable t); + +} diff --git a/app-base/src/main/java/com/cain/base/base/logs/LogcatLogger.java b/app-base/src/main/java/com/cain/base/base/logs/LogcatLogger.java new file mode 100644 index 0000000..8c65619 --- /dev/null +++ b/app-base/src/main/java/com/cain/base/base/logs/LogcatLogger.java @@ -0,0 +1,119 @@ +package com.cain.base.base.logs; + +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.xuexiang.xui.logs.ILogger; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 默认Logcat日志记录 + * + * @author xuexiang + * @since 2019年1月14日 下午10:14 + */ +public class LogcatLogger implements ILogger { + + /** + * logcat里日志的最大长度. + */ + private static final int MAX_LOG_LENGTH = 4000; + + /** + * 打印信息 + * + * @param priority 优先级 + * @param tag 标签 + * @param message 信息 + * @param t 出错信息 + */ + @Override + public void log(int priority, String tag, String message, Throwable t) { + if (message != null && message.length() == 0) { + message = null; + } + if (message == null) { + if (t == null) { + return; // Swallow message if it's null and there's no throwable. + } + message = getStackTraceString(t); + } else { + if (t != null) { + message += "\n" + getStackTraceString(t); + } + } + + log(priority, tag, message); + } + + private String getStackTraceString(Throwable t) { + // Don't replace this with Log.getStackTraceString() - it hides + // UnknownHostException, which is not what we want. + StringWriter sw = new StringWriter(256); + PrintWriter pw = new PrintWriter(sw, false); + t.printStackTrace(pw); + pw.flush(); + return sw.toString(); + } + + + /** + * 使用LogCat输出日志,字符长度超过4000则自动换行. + * + * @param priority 优先级 + * @param tag 标签 + * @param message 信息 + */ + public void log(int priority, String tag, String message) { + int subNum = message.length() / MAX_LOG_LENGTH; + if (subNum> 0) { + int index = 0; + for (int i = 0; i < subNum; i++) { + int lastIndex = index + MAX_LOG_LENGTH; + String sub = message.substring(index, lastIndex); + logSub(priority, tag, sub); + index = lastIndex; + } + logSub(priority, tag, message.substring(index, message.length())); + } else { + logSub(priority, tag, message); + } + } + + + /** + * 使用LogCat输出日志. + * + * @param priority 优先级 + * @param tag 标签 + * @param sub 信息 + */ + private void logSub(int priority, @NonNull String tag, @NonNull String sub) { + switch (priority) { + case Log.VERBOSE: + Log.v(tag, sub); + break; + case Log.DEBUG: + Log.d(tag, sub); + break; + case Log.INFO: + Log.i(tag, sub); + break; + case Log.WARN: + Log.w(tag, sub); + break; + case Log.ERROR: + Log.e(tag, sub); + break; + case Log.ASSERT: + Log.wtf(tag, sub); + break; + default: + Log.v(tag, sub); + break; + } + } +} diff --git a/app-base/src/main/java/com/cain/base/base/logs/UILog.java b/app-base/src/main/java/com/cain/base/base/logs/UILog.java new file mode 100644 index 0000000..5692701 --- /dev/null +++ b/app-base/src/main/java/com/cain/base/base/logs/UILog.java @@ -0,0 +1,315 @@ +package com.cain.base.base.logs; + +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.xuexiang.xui.logs.ILogger; +import com.xuexiang.xui.logs.LogcatLogger; + +/** + * 框架日志记录 + * + * @author xuexiang + * @since 2018/11/14 上午11:59 + */ +public final class UILog { + + //==============常量================// + /** + * 默认tag + */ + private final static String DEFAULT_LOG_TAG = "[XUI]"; + /** + * 最大日志优先级【日志优先级为最大等级,所有日志都不打印】 + */ + private final static int MAX_LOG_PRIORITY = 10; + /** + * 最小日志优先级【日志优先级为最小等级,所有日志都打印】 + */ + private final static int MIN_LOG_PRIORITY = 0; + + //==============属性================// + /** + * 默认的日志记录为Logcat + */ + private static ILogger sILogger = new LogcatLogger(); + + private static String sTag = DEFAULT_LOG_TAG; + /** + * 是否是调试模式 + */ + private static boolean sIsDebug = false; + /** + * 日志打印优先级 + */ + private static int sLogPriority = MAX_LOG_PRIORITY; + + //==============属性设置================// + + /** + * 设置日志记录者的接口 + * + * @param logger + */ + public static void setLogger(@NonNull ILogger logger) { + sILogger = logger; + } + + /** + * 设置日志的tag + * + * @param tag + */ + public static void setTag(String tag) { + sTag = tag; + } + + /** + * 设置是否是调试模式 + * + * @param isDebug + */ + public static void setDebug(boolean isDebug) { + sIsDebug = isDebug; + } + + /** + * 设置打印日志的等级(只打印改等级以上的日志) + * + * @param priority + */ + public static void setPriority(int priority) { + sLogPriority = priority; + } + + //===================对外接口=======================// + + /** + * 设置是否打开调试 + * @param isDebug + */ + public static void debug(boolean isDebug) { + if (isDebug) { + debug(DEFAULT_LOG_TAG); + } else { + debug(""); + } + } + + /** + * 设置调试模式 + * + * @param tag + */ + public static void debug(String tag) { + if (!TextUtils.isEmpty(tag)) { + setDebug(true); + setPriority(MIN_LOG_PRIORITY); + setTag(tag); + } else { + setDebug(false); + setPriority(MAX_LOG_PRIORITY); + setTag(""); + } + } + + //=============打印方法===============// + /** + * 打印任何(所有)信息 + * + * @param msg + */ + public static void v(String msg) { + if (enableLog(Log.VERBOSE)) { + sILogger.log(Log.VERBOSE, sTag, msg, null); + } + } + + /** + * 打印任何(所有)信息 + * + * @param tag + * @param msg + */ + public static void vTag(String tag, String msg) { + if (enableLog(Log.VERBOSE)) { + sILogger.log(Log.VERBOSE, tag, msg, null); + } + } + + /** + * 打印调试信息 + * + * @param msg + */ + public static void d(String msg) { + if (enableLog(Log.DEBUG)) { + sILogger.log(Log.DEBUG, sTag, msg, null); + } + } + + /** + * 打印调试信息 + * + * @param tag + * @param msg + */ + public static void dTag(String tag, String msg) { + if (enableLog(Log.DEBUG)) { + sILogger.log(Log.DEBUG, tag, msg, null); + } + } + + /** + * 打印提示性的信息 + * + * @param msg + */ + public static void i(String msg) { + if (enableLog(Log.INFO)) { + sILogger.log(Log.INFO, sTag, msg, null); + } + } + + /** + * 打印提示性的信息 + * + * @param tag + * @param msg + */ + public static void iTag(String tag, String msg) { + if (enableLog(Log.INFO)) { + sILogger.log(Log.INFO, tag, msg, null); + } + } + + /** + * 打印warning警告信息 + * + * @param msg + */ + public static void w(String msg) { + if (enableLog(Log.WARN)) { + sILogger.log(Log.WARN, sTag, msg, null); + } + } + + /** + * 打印warning警告信息 + * + * @param tag + * @param msg + */ + public static void wTag(String tag, String msg) { + if (enableLog(Log.WARN)) { + sILogger.log(Log.WARN, tag, msg, null); + } + } + + /** + * 打印出错信息 + * + * @param msg + */ + public static void e(String msg) { + if (enableLog(Log.ERROR)) { + sILogger.log(Log.ERROR, sTag, msg, null); + } + } + + /** + * 打印出错信息 + * + * @param tag + * @param msg + */ + public static void eTag(String tag, String msg) { + if (enableLog(Log.ERROR)) { + sILogger.log(Log.ERROR, tag, msg, null); + } + } + + /** + * 打印出错堆栈信息 + * + * @param t + */ + public static void e(Throwable t) { + if (enableLog(Log.ERROR)) { + sILogger.log(Log.ERROR, sTag, null, t); + } + } + + /** + * 打印出错堆栈信息 + * + * @param tag + * @param t + */ + public static void eTag(String tag, Throwable t) { + if (enableLog(Log.ERROR)) { + sILogger.log(Log.ERROR, tag, null, t); + } + } + + + /** + * 打印出错堆栈信息 + * + * @param msg + * @param t + */ + public static void e(String msg, Throwable t) { + if (enableLog(Log.ERROR)) { + sILogger.log(Log.ERROR, sTag, msg, t); + } + } + + /** + * 打印出错堆栈信息 + * + * @param tag + * @param msg + * @param t + */ + public static void eTag(String tag, String msg, Throwable t) { + if (enableLog(Log.ERROR)) { + sILogger.log(Log.ERROR, tag, msg, t); + } + } + + /** + * 打印严重的错误信息 + * + * @param msg + */ + public static void wtf(String msg) { + if (enableLog(Log.ASSERT)) { + sILogger.log(Log.ASSERT, sTag, msg, null); + } + } + + /** + * 打印严重的错误信息 + * + * @param tag + * @param msg + */ + public static void wtfTag(String tag, String msg) { + if (enableLog(Log.ASSERT)) { + sILogger.log(Log.ASSERT, tag, msg, null); + } + } + + /** + * 能否打印 + * + * @param logPriority + * @return + */ + private static boolean enableLog(int logPriority) { + return sILogger != null && sIsDebug && logPriority>= sLogPriority; + } +} diff --git a/app-util-sub/build.gradle b/app-util-sub/build.gradle index bccf71b..e5b2d8a 100644 --- a/app-util-sub/build.gradle +++ b/app-util-sub/build.gradle @@ -1,14 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 29 - buildToolsVersion "29.0.3" + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools defaultConfig { - minSdkVersion 21 - targetSdkVersion 29 - versionCode 1 - versionName "1.0" + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' @@ -32,6 +30,8 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation deps.support.v4 + compileOnly deps.support.app_compat compileOnly deps.support.design implementation project(path: ':app-util') diff --git a/app-util-sub/src/main/AndroidManifest.xml b/app-util-sub/src/main/AndroidManifest.xml index 447cbb0..0c1baaf 100644 --- a/app-util-sub/src/main/AndroidManifest.xml +++ b/app-util-sub/src/main/AndroidManifest.xml @@ -1,5 +1,57 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.cain.util.sub"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/app-util-sub/src/main/java/com/cain/util/sub/app/router/Router.java b/app-util-sub/src/main/java/com/cain/util/sub/app/router/Router.java index 0c2796e..d210b06 100644 --- a/app-util-sub/src/main/java/com/cain/util/sub/app/router/Router.java +++ b/app-util-sub/src/main/java/com/cain/util/sub/app/router/Router.java @@ -21,11 +21,13 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.ActivityOptionsCompat; -import com.xuexiang.xutil.app.IntentUtils; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.app.ActivityOptionsCompat; + +import com.cain.util.xutil.app.IntentUtils; + /** *
@@ -36,14 +38,14 @@
 */
 public class Router {
 // #router
- public static final int ROUTER_ANIM_ENTER = Router.RES_NONE;
+ /* public static final int ROUTER_ANIM_ENTER = Router.RES_NONE;
 public static final int ROUTER_ANIM_EXIT = Router.RES_NONE;
 
 private Intent intent;
 private Activity fromActivity;
 
 private Fragment fromFragment;
- private android.support.v4.app.Fragment fromFragmentV4;
+ private Fragment fromFragmentV4;
 
 private Class to;
 private Bundle data;
@@ -201,5 +203,5 @@ public static void pop(Activity activity) {
 
 public static void setCallback(RouterCallback callback) {
 Router.callback = callback;
- }
+ }*/
 }
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/common/IDCardUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/common/IDCardUtils.java
index c7ee5c6..4ab007f 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/common/IDCardUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/common/IDCardUtils.java
@@ -15,7 +15,9 @@
 */
 package com.cain.util.sub.common;
 
-import com.xuexiang.xutil.data.DateUtils;
+
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.data.DateUtils;
 
 import java.text.DateFormat;
 import java.text.ParseException;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/common/SpanUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/common/SpanUtils.java
index cac756b..e35bc67 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/common/SpanUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/common/SpanUtils.java
@@ -30,14 +30,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
 import android.text.Layout;
 import android.text.Layout.Alignment;
 import android.text.SpannableStringBuilder;
@@ -65,7 +57,16 @@
 import android.text.style.UpdateAppearance;
 import android.util.Log;
 
-import com.xuexiang.xutil.XUtil;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+
+import com.cain.util.xutil.XUtil;
 
 import java.io.InputStream;
 import java.lang.annotation.Retention;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/display/DrawableUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/display/DrawableUtils.java
index b2e81ce..abb1145 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/display/DrawableUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/display/DrawableUtils.java
@@ -23,6 +23,8 @@
 import android.graphics.drawable.StateListDrawable;
 import android.widget.TextView;
 
+import com.cain.util.xutil.display.ColorUtils;
+
 /**
 * Drawable生成工具类
 *
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/display/SnackbarUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/display/SnackbarUtils.java
index 4784d1e..48be8c6 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/display/SnackbarUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/display/SnackbarUtils.java
@@ -16,13 +16,6 @@
 
 package com.cain.util.sub.display;
 
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.style.ForegroundColorSpan;
@@ -30,6 +23,15 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+
+import com.google.android.material.snackbar.Snackbar;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/CameraUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/CameraUtils.java
index 4b8761e..240dd2d 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/CameraUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/CameraUtils.java
@@ -21,11 +21,12 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.MediaStore;
-import android.support.v4.app.Fragment;
 import android.text.TextUtils;
 
-import com.xuexiang.xutil.app.PathUtils;
-import com.xuexiang.xutil.file.FileUtils;
+import androidx.fragment.app.Fragment;
+
+import com.cain.util.xutil.app.PathUtils;
+import com.cain.util.xutil.file.FileUtils;
 
 import java.io.File;
 import java.text.SimpleDateFormat;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/ClipboardUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/ClipboardUtils.java
index d82d57a..c42bdf0 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/ClipboardUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/ClipboardUtils.java
@@ -21,8 +21,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
+
+import com.cain.util.xutil.XUtil;
 
-import com.xuexiang.xutil.XUtil;
 
 /**
 * 
@@ -54,6 +58,7 @@ public static void copyText(final CharSequence text) {
 *
 * @return 剪贴板的文本
 */
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public static CharSequence getText() {
 ClipboardManager clipboard = (ClipboardManager) XUtil.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
 if (clipboard != null) {
@@ -70,6 +75,7 @@ public static CharSequence getText() {
 *
 * @param uri uri
 */
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public static void copyUri(final Uri uri) {
 ClipboardManager clipboard = (ClipboardManager) XUtil.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
 if (clipboard != null) {
@@ -82,6 +88,7 @@ public static void copyUri(final Uri uri) {
 *
 * @return 剪贴板的uri
 */
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public static Uri getUri() {
 ClipboardManager clipboard = (ClipboardManager) XUtil.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
 ClipData clip = clipboard.getPrimaryClip();
@@ -96,6 +103,7 @@ public static Uri getUri() {
 *
 * @param intent 意图
 */
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public static void copyIntent(final Intent intent) {
 ClipboardManager clipboard = (ClipboardManager) XUtil.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
 if (clipboard != null) {
@@ -108,6 +116,7 @@ public static void copyIntent(final Intent intent) {
 *
 * @return 剪贴板的意图
 */
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public static Intent getIntent() {
 ClipboardManager clipboard = (ClipboardManager) XUtil.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
 if (clipboard != null) {
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/DeviceStatusUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/DeviceStatusUtils.java
index cff27f2..4831753 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/DeviceStatusUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/DeviceStatusUtils.java
@@ -25,11 +25,12 @@
 import android.media.AudioManager;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.RequiresPermission;
 import android.view.Window;
 import android.view.WindowManager;
 
-import com.xuexiang.xutil.common.StringUtils;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.common.StringUtils;
 
 import static android.Manifest.permission.WRITE_APN_SETTINGS;
 import static android.Manifest.permission.WRITE_SETTINGS;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/EditTextShakeHelper.java b/app-util-sub/src/main/java/com/cain/util/sub/system/EditTextShakeHelper.java
index a0953cb..d2c17eb 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/EditTextShakeHelper.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/EditTextShakeHelper.java
@@ -23,7 +23,8 @@
 import android.view.animation.TranslateAnimation;
 import android.widget.EditText;
 
-import com.xuexiang.xutil.XUtil;
+import com.cain.util.xutil.XUtil;
+
 
 /**
 * 
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/FlashlightUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/FlashlightUtils.java
index e75fc9f..4565965 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/FlashlightUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/FlashlightUtils.java
@@ -21,7 +21,7 @@
 import android.hardware.Camera;
 import android.util.Log;
 
-import com.xuexiang.xutil.XUtil;
+import com.cain.util.xutil.XUtil;
 
 import java.io.IOException;
 
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/PhoneUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/PhoneUtils.java
index fba18ef..4f55ef0 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/PhoneUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/PhoneUtils.java
@@ -21,13 +21,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
-import android.support.annotation.RequiresPermission;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.app.IntentUtils;
-import com.xuexiang.xutil.common.StringUtils;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.app.IntentUtils;
+import com.cain.util.xutil.common.StringUtils;
 
 import java.lang.reflect.Method;
 import java.util.List;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/RomUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/RomUtils.java
index 730b401..26ca154 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/RomUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/RomUtils.java
@@ -19,9 +19,10 @@
 import android.annotation.SuppressLint;
 import android.os.Build;
 import android.os.Environment;
-import android.support.annotation.NonNull;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/ThreadPoolManager.java b/app-util-sub/src/main/java/com/cain/util/sub/system/ThreadPoolManager.java
index 98813ba..558cf82 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/ThreadPoolManager.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/ThreadPoolManager.java
@@ -16,6 +16,8 @@
 
 package com.cain.util.sub.system;
 
+import com.cain.util.xutil.system.ThreadPoolUtils;
+
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -25,7 +27,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import static com.xuexiang.xutil.system.ThreadPoolUtils.FixedThread;
+import static com.cain.util.xutil.system.ThreadPoolUtils.FixedThread;
+
 
 /**
 * 
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BLEHelper.java b/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BLEHelper.java
index 57d4ea5..65490d7 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BLEHelper.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BLEHelper.java
@@ -21,7 +21,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.os.CountDownTimer;
 
-import com.xuexiang.xutil.system.ThreadPoolManager;
+import com.cain.util.sub.system.ThreadPoolManager;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BluetoothHelper.java b/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BluetoothHelper.java
index 64826dd..fa9f7f6 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BluetoothHelper.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/bt/BluetoothHelper.java
@@ -24,10 +24,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.system.ThreadPoolManager;
-import com.xuexiang.xutil.tip.ToastUtils;
+import com.cain.util.sub.system.ThreadPoolManager;
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.tip.ToastUtils;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPHelper.java b/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPHelper.java
index cf52313..5358f87 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPHelper.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPHelper.java
@@ -21,11 +21,12 @@
 import android.os.Handler;
 import android.os.Looper;
 
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.net.NetworkUtils;
-import com.xuexiang.xutil.system.ThreadPoolManager;
-import com.xuexiang.xutil.tip.ToastUtils;
-import com.xuexiang.xutil_sub.R;
+import com.cain.util.sub.R;
+import com.cain.util.sub.system.ThreadPoolManager;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.net.NetworkUtils;
+import com.cain.util.xutil.tip.ToastUtils;
+
 
 /**
 * 
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPUtils.java b/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPUtils.java
index 69696a7..3a15f65 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPUtils.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiAPUtils.java
@@ -20,7 +20,7 @@
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 
-import com.xuexiang.xutil.net.NetworkUtils;
+import com.cain.util.xutil.net.NetworkUtils;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiHelper.java b/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiHelper.java
index d85d49a..f810062 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiHelper.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/system/wifi/WifiHelper.java
@@ -22,10 +22,10 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
 
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.common.logger.Logger;
-import com.xuexiang.xutil.net.NetworkUtils;
-import com.xuexiang.xutil.system.ThreadPoolManager;
+import com.cain.util.sub.system.ThreadPoolManager;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.common.logger.Logger;
+import com.cain.util.xutil.net.NetworkUtils;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/type/TypeBuilder.java b/app-util-sub/src/main/java/com/cain/util/sub/type/TypeBuilder.java
index 1007498..35a2531 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/type/TypeBuilder.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/type/TypeBuilder.java
@@ -16,8 +16,9 @@
 
 package com.cain.util.sub.type;
 
-import com.xuexiang.xutil.net.type.impl.ParameterizedTypeImpl;
-import com.xuexiang.xutil.net.type.impl.WildcardTypeImpl;
+
+import com.cain.util.sub.type.impl.ParameterizedTypeImpl;
+import com.cain.util.sub.type.impl.WildcardTypeImpl;
 
 import java.lang.reflect.Type;
 import java.util.ArrayList;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/type/impl/ParameterizedTypeImpl.java b/app-util-sub/src/main/java/com/cain/util/sub/type/impl/ParameterizedTypeImpl.java
index 4868b5d..8ab8f16 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/type/impl/ParameterizedTypeImpl.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/type/impl/ParameterizedTypeImpl.java
@@ -16,9 +16,10 @@
 
 package com.cain.util.sub.type.impl;
 
-import android.support.annotation.NonNull;
 
-import com.xuexiang.xutil.net.type.TypeException;
+import androidx.annotation.NonNull;
+
+import com.cain.util.sub.type.TypeException;
 
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
diff --git a/app-util-sub/src/main/java/com/cain/util/sub/type/impl/WildcardTypeImpl.java b/app-util-sub/src/main/java/com/cain/util/sub/type/impl/WildcardTypeImpl.java
index 7a43d11..7774b90 100644
--- a/app-util-sub/src/main/java/com/cain/util/sub/type/impl/WildcardTypeImpl.java
+++ b/app-util-sub/src/main/java/com/cain/util/sub/type/impl/WildcardTypeImpl.java
@@ -16,7 +16,8 @@
 
 package com.cain.util.sub.type.impl;
 
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.lang.reflect.Type;
 import java.lang.reflect.WildcardType;
diff --git a/app-util-sub/src/main/res/values/xutil_strings.xml b/app-util-sub/src/main/res/values/xutil_strings.xml
new file mode 100644
index 0000000..bc2ffd6
--- /dev/null
+++ b/app-util-sub/src/main/res/values/xutil_strings.xml
@@ -0,0 +1,7 @@
+
+
+ 打开热点失败,请到系统设置里检查热点状态!
+ 已开启WLAN热点
+ 已关闭WLAN热点!
+ 已关闭WiFi
+
diff --git a/app-util/README.md b/app-util/README.md
new file mode 100644
index 0000000..a93c3db
--- /dev/null
+++ b/app-util/README.md
@@ -0,0 +1,769 @@
+# XUtil-Core
+
+核心基础的Android工具类库
+
+## 在线文档
+
+[点击查看【v1.1.7】](https://jitpack.io/com/github/xuexiangjys/XUtil/xutil-core/1.1.7/javadoc/)
+
+## APIs
+
+* ### ActivityUtils -> Activity页面跳转工具类
+
+```
+startActivity : 页面跳转
+startActivityForResult : 页面跳转,返回数据
+getActivityIntent : 获取Activity跳转意图
+```
+
+* ### AppUtils -> App 相关工具类
+
+```
+isInstallApp : 判断 App 是否安装
+installApp : 安装 App(支持 8.0)
+uninstallApp : 卸载 App
+isAppRoot : 判断 App 是否有 root 权限
+launchApp : 打开 App
+exitApp : 退出 App
+getAppPackageName : 获取 App 包名
+getAppDetailsSettings : 获取 App 具体设置
+getAppName : 获取 App 名称
+getAppIcon : 获取 App 图标
+getAppPath : 获取 App 路径
+getAppVersionName : 获取 App 版本号
+getAppVersionCode : 获取 App 版本码
+isSystemApp : 判断 App 是否是系统应用
+isAppDebug : 判断 App 是否是 Debug 版本
+getAppSignature : 获取 App 签名
+getAppSignatureSHA1 : 获取应用签名的的 SHA1 值
+isAppForeground : 判断 App 是否处于前台
+getAppInfo : 获取 App 信息
+getAppsInfo : 获取所有已安装 App 信息
+cleanAppData : 清除 App 所有数据
+
+```
+
+* ### BroadcastUtils -> 广播工具类
+
+```
+getBroadCastIntent : 获取广播意图
+sendBroadCast : 发广播
+registerReceiver : 注册广播接收器
+unregisterReceiver : 注销广播接收器
+```
+
+* ### IntentUtils -> 意图相关工具类
+
+```
+getInstallAppIntent : 获取安装 App(支持 8.0)的意图
+getUninstallAppIntent : 获取卸载 App 的意图
+getLaunchAppIntent : 获取打开 App 的意图
+getAppDetailsSettingsIntent : 获取 App 具体设置的意图
+getShareTextIntent : 获取分享文本的意图
+getShareImageIntent : 获取分享图片的意图
+getComponentIntent : 获取其他应用组件的意图
+getShutdownIntent : 获取关机的意图
+getDialIntent : 获取跳至拨号界面意图
+getCallIntent : 获取拨打电话意图
+getSendSmsIntent : 获取发送短信界面的意图
+getCaptureIntent : 获取拍照的意图
+getExtras : 获取附加数据
+getBundleExtra : 获取Intent中的Bundle数据
+getStringExtra : 获取Intent中的String数据
+getBooleanExtra : 获取Intent中的Boolean数据
+getIntExtra : 获取Intent中的Int数据
+getFloatExtra : 获取Intent中的Float数据
+getSerializableExtra : 获取Intent中的Serializable数据
+getBundleSerializable : 获取Intent中的Bundle携带的Serializable数据
+getIntent : 获取Intent意图
+putExtra : 向Intent中传递数据
+putBundle : 向Bundle中传递数据
+getPickIntentWithGallery : 获取选择照片的 Intent
+getPickIntentWithDocuments : 获取从文件中选择照片的 Intent
+getDocumentPickerIntent : 获取文件选择的 Intent
+```
+
+* ### ProcessUtils -> 进程相关工具类
+
+```
+getForegroundProcessName : 获取前台线程包名
+getAllBackgroundProcesses : 获取后台服务进程
+killAllBackgroundProcesses : 杀死所有的后台服务进程
+killBackgroundProcesses : 杀死后台服务进程
+gc : 清理后台进程与服务
+isMainProcess : 判断应用当前所处进程是否是主进程
+getCurrentProcessName : 获取当前进程的名字
+```
+
+* ### ServiceUtils -> 服务相关工具类
+
+```
+getAllRunningService : 获取所有运行的服务
+startService : 启动服务
+stopService : 停止服务
+bindService : 绑定服务
+unbindService : 解绑服务
+isServiceRunning : 判断服务是否运行
+stopAllRunningService : 停止指定应用的所以运行的服务
+```
+
+* ### Logger -> Logger日志记录
+
+```
+setLogger : 设置日志记录者的接口
+setTag : 设置日志的tag
+setDebug : 设置是否是调试模式
+setPriority : 设置打印日志的等级(只打印改等级以上的日志)
+debug : 设置是否打开调试
+v : 打印任何(所有)信息
+vTag : 打印任何(所有)信息
+d : 打印调试信息
+dTag : 打印调试信息
+i : 打印提示性的信息
+iTag : 打印提示性的信息
+w : 打印warning警告信息
+wTag : 打印warning警告信息
+e : 打印出错信息
+eTag : 打印出错信息
+wtf : 打印严重的错误信息
+wtfTag : 打印严重的错误信息
+```
+
+* ### ClickUtils -> 快速点击工具类
+
+```
+isFastDoubleClick : 是否是快速点击
+exitBy2Click : 双击返回退出程序
+```
+
+* ### ObjectUtils -> 对象相关工具类
+
+```
+isEmpty : 返回object是否为空
+isNotEmpty : 返回object是否不为空
+equals : 返回两个对象是否相等
+requireNonNull : 判断对象是否为null,为null就直接抛出空指针异常
+getOrDefault : 返回一个非空的对象或者默认值
+```
+
+* ### ShellUtils -> shell命令工具类
+
+```
+checkRootPermission : 验证是否获取root权限
+execCommand : 执行shell命令
+```
+
+* ### StringUtils -> String相关工具类
+
+```
+isEmpty : 判断字符串是否为 null 或长度为 0
+isEmptyTrim : 判断字符串是否为 null 或全为空格
+toInt : String转Int(防止崩溃)
+toFloat : String转Float(防止崩溃)
+toShort : String转Short(防止崩溃)
+toLong : String转Long(防止崩溃)
+toDouble : String转Double(防止崩溃)
+toBoolean : String转Boolean(防止崩溃)
+getString : 获取String内容
+isInteger : 判断字符串是否是整数
+isDouble : 判断字符串是否是双精度浮点数
+isNumber : 判断字符串是否是数字
+isSpace : 判断字符串是否为 null 或全为空白字符
+equals : 判断两字符串是否相等
+equalsIgnoreCase : 判断两字符串忽略大小写是否相等
+length : 返回字符串长度
+upperFirstLetter : 首字母大写
+lowerFirstLetter : 首字母小写
+reverse : 反转字符串
+getStackTraceString : 获取异常栈信息,不同于Log.getStackTraceString(),该方法不会过滤掉UnknownHostException.
+concat : 字符串连接,将参数列表拼接为一个字符串
+concatSpiltWith : 字符串连接,将参数列表通过分隔符拼接为一个字符串
+contains : 判断一个数组里是否包含指定对象
+toString : 将对象转化为String
+replaceSpecialCharacter : 过滤字符串中所有的特殊字符
+replaceBracket : 过滤字符串中的[和]
+replaceBlank : 过滤字符串中的空格
+stringToList : 根据分隔符将String转换为List
+listToString : 根据分隔符将List转换为String
+getSimpleName : 获取对象的类名
+format2Decimals : 将字符串格式化为带两位小数的字符串
+compareVersionName : 比较两个版本号
+```
+
+* ### ACache -> 缓存相关工具类【键值对存储】
+
+```
+get : 获取缓存实例
+get().put : 缓存中写入数据
+get().getBytes : 缓存中读取字节数组
+get().getString : 缓存中读取 String
+get().getJSONObject : 缓存中读取 JSONObject
+get().getJSONArray : 缓存中读取 JSONArray
+get().getBitmap : 缓存中读取 Bitmap
+get().getDrawable : 缓存中读取 Drawable
+get().getParcelable : 缓存中读取 Parcelable
+get().getSerializable: 缓存中读取 Serializable
+get().getCacheSize : 获取缓存大小
+get().getCacheCount : 获取缓存个数
+get().remove : 根据键值移除缓存
+get().clear : 清除所有缓存
+```
+
+* ### CloneUtils -> 克隆相关工具类
+
+```
+deepClone : 深度克隆对象
+```
+
+* ### ConvertTools -> 转换相关工具类
+
+```
+byte2HexString : 一个byte转16进制String
+bytes2HexString : byte数组转16进制String
+hexStringToByteArray : 16进制表示的字符串转换为字节数组
+byteToIntUnSigned : 一位byte转int【无符号】
+byteToIntSigned : 一位byte转int【有符号】
+intToByte : int转Byte 【仅对0~255的整型有效】
+intToBytesLittleEndian : 将int数值转换为占四个字节的byte数组,本方法适用于(【小端】低位在前,高位在后)的顺序。
+fillIntToBytesLittleEndian : 将int数值填充至byte数组的指定位置,本方法适用于(【小端】低位在前,高位在后)的顺序。
+intToBytesBigEndian : 将int数值转换为占四个字节的byte数组,本方法适用于(【大端】高位在前,低位在后)的顺序。
+fillIntToBytesBigEndian : 将int数值填充至byte数组的指定位置,本方法适用于(【大端】高位在前,低位在后)的顺序。
+bytesToIntLittleEndian : byte数组中取int数值,本方法适用于(【小端】低位在前,高位在后)的顺序
+bytesToIntBigEndian : byte数组中取int数值,本方法适用于(【大端】高位在前,低位在后)的顺序。
+shortToBytesLittleEndian : 将short数值转换为占两个字节的byte数组,本方法适用于(【小端】低位在前,高位在后)的顺序。
+fillShortToBytesLittleEndian : 将short数值填充至byte数组的指定位置,本方法适用于(【小端】低位在前,高位在后)的顺序
+fillUnsignedShortToBytesLittleEndian : 将无符号short数值填充至byte数组的指定位置,本方法适用于(【小端】低位在前,高位在后)的顺序
+shortToBytesBigEndian : 将short数值转换为占两个字节的byte数组,本方法适用于(【大端】高位在前,低位在后)的顺序。
+fillShortToBytesBigEndian : 将short数值填充至byte数组的指定位置,本方法适用于(【大端】高位在前,低位在后)的顺序
+fillUnsignedShortToBytesBigEndian : 将无符号short数值填充至byte数组的指定位置,本方法适用于(【大端】高位在前,低位在后)的顺序
+bytesToShortLittleEndian : byte数组中取short数值,本方法适用于(【小端】低位在前,高位在后)的顺序
+bytesToShortBigEndian : byte数组中取short数值,本方法适用于(【大端】高位在前,低位在后)的顺序
+```
+
+
+* ### DateUtils -> 日期时间工具类
+
+```
+millis2String : 将时间戳转为时间字符串
+date2String : 将 Date 类型转为时间字符串
+string2Millis : 将时间字符串转为时间戳
+string2Date : 将时间字符串转为 Date 类型
+date2Millis : 将 Date 类型转为时间戳
+millis2Date : 将时间戳转为 Date 类型
+translateDateFormat : 转换日期格式 oldFormat ---> newFormat
+isDateFormatRight : 判断时间字符串的格式是否正确
+nDaysBeforeToday : 获取当前日期n天前的日期,返回String
+nDaysAfterToday : 获取当前日期n天后的日期,返回String
+getTimeSpan : 获取两个时间差(单位:unit)
+getFitTimeSpan : 获取合适型两个时间差
+getTimeSpanByNow : 获取与当前时间的差(单位:unit)
+getFitTimeSpanByNow : 获取合适型与当前时间的差
+getFriendlyTimeSpanByNow : 获取友好型与当前时间的差
+getFuzzyTimeDescriptionByNow : 根据时间戳获取模糊型的时间描述。
+getAgeByBirthDay : 根据出生日期获取年龄
+getNowMills : 获取当前毫秒时间戳
+getNowString : 获取当前时间字符串
+getNowDate : 获取当前 Date
+isToday : 判断是否今天
+getWeekIndex : 获取星期索引
+getYear : 得到年份
+getMonth : 得到月
+getDay : 得到日
+getChineseZodiac : 获取生肖
+getZodiac : 获取星座
+```
+
+* ### SPUtils -> SharedPreferences工具类
+
+```
+getSharedPreferences : 获取SharedPreferences实例
+putBoolean : 设置boolean值
+putFloat : 设置float值
+putLong : 设置long值
+putString : 设置String值
+putInt : 设置int值
+putObject : 设置Object
+putEncodeObject : 设置加密Object
+put : 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
+getBoolean : 根据key获取boolean值
+getLong : 根据key获取long值
+getFloat : 根据key获取float值
+getString : 根据key获取String值
+getInt : 根据key获取int值
+getEncodeObject : 获取加密的对象
+getObject : 获取对象
+get : 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
+contains : 查询某个key是否已经存在
+getAll : 返回所有的键值对
+remove : 去除某一键值对
+clear : 清空销毁
+```
+
+* ### BarUtils -> 栏相关
+```
+getStatusBarHeight : 获取状态栏高度(px)
+setStatusBarVisibility : 设置状态栏是否可见
+isStatusBarVisible : 判断状态栏是否可见
+setStatusBarLightMode : 设置状态栏是否为浅色模式
+addMarginTopEqualStatusBarHeight : 为 view 增加 MarginTop 为状态栏高度
+subtractMarginTopEqualStatusBarHeight: 为 view 减少 MarginTop 为状态栏高度
+setStatusBarColor : 设置状态栏颜色
+setStatusBarAlpha : 设置状态栏透明度
+setStatusBarColor4Drawer : 为 DrawerLayout 设置状态栏颜色
+setStatusBarAlpha4Drawer : 为 DrawerLayout 设置状态栏透明度
+getActionBarHeight : 获取 ActionBar 高度
+setNotificationBarVisibility : 设置通知栏是否可见
+getNavBarHeight : 获取导航栏高度
+setNavBarVisibility : 设置导航栏是否可见
+setNavBarImmersive : 设置导航栏沉浸式
+setNavBarColor : 设置导航栏颜色
+getNavBarColor : 获取导航栏颜色
+isNavBarVisible : 判断导航栏是否可见
+```
+
+* ### ColorUtils -> 颜色相关工具类
+
+```
+adjustAlpha : 矫正颜色的透明度
+setColorAlpha : 设置颜色的alpha值
+colorToString : 将 color 颜色值转换为十六进制字符串
+darker : 加深颜色
+lighter : 变浅颜色
+isColorDark : 是否是深色的颜色
+getStateColor : 获取某状态颜色
+getEnableColor : 获取可点击时的颜色
+getDisableColor : 获取不可点击时的颜色
+getDefaultColor : 获取默认的颜色
+getRandomColor : 获取随机颜色
+```
+
+* ### DensityUtils -> 屏幕密度工具类
+
+```
+dip2px : 根据手机的分辨率从 dp 的单位 转成为 px(像素)
+px2dip : 根据手机的分辨率从 px(像素) 的单位 转成为 dp
+sp2px : 根据手机的分辨率从 sp 的单位 转成为 px
+px2sp : 根据手机的分辨率从 px(像素) 的单位 转成为 sp
+getScreenDpi : 获取屏幕分辨率
+getScreenWidth : 得到设备屏幕的宽度
+getScreenHeight : 得到设备屏幕的高度
+getScreenDensity : 得到设备的密度
+```
+
+* ### ImageUtils -> 图片相关工具类
+
+```
+bitmap2Bytes, bytes2Bitmap : bitmap 与 bytes 互转
+drawable2Bitmap, bitmap2Drawable: drawable 与 bitmap 互转
+drawable2Bytes, bytes2Drawable : drawable 与 bytes 互转
+view2Bitmap : view 转 bitmap
+getBitmap : 获取 bitmap
+scale : 缩放图片
+clearImgMemory : 清空图片的内存
+clip : 裁剪图片
+skew : 倾斜图片
+rotate : 旋转图片
+getRotateDegree : 获取图片旋转角度
+toRound : 转为圆形图片
+toRoundCorner : 转为圆角图片
+addCornerBorder : 添加圆角边框
+addCircleBorder : 添加圆形边框
+addReflection : 添加倒影
+addTextWatermark : 添加文字水印
+addImageWatermark : 添加图片水印
+toAlpha : 转为 alpha 位图
+toGray : 转为灰度图片
+fastBlur : 快速模糊
+renderScriptBlur : renderScript 模糊图片
+stackBlur : stack 模糊图片
+save : 保存图片
+isImage : 根据文件名判断文件是否为图片
+getImageType : 获取图片类型
+compressByScale : 按缩放压缩
+compressByQuality : 按质量压缩
+compressBySampleSize : 按采样大小压缩
+```
+
+* ### ScreenUtils -> 屏幕相关工具类
+
+```
+getScreenWidth : 获取屏幕的宽度(单位:px)
+getScreenHeight : 获取屏幕的高度(单位:px)
+getScreenDensity : 获取屏幕密度
+getScreenDensityDpi: 获取屏幕密度 DPI
+setFullScreen : 设置屏幕为全屏
+setLandscape : 设置屏幕为横屏
+setPortrait : 设置屏幕为竖屏
+isLandscape : 判断是否横屏
+isPortrait : 判断是否竖屏
+getScreenRotation : 获取屏幕旋转角度
+screenShot : 截屏
+isScreenLock : 判断是否锁屏
+setSleepDuration : 设置进入休眠时长
+getSleepDuration : 获取进入休眠时长
+isTablet : 判断是否是平板
+```
+
+* ### ViewUtils -> View控件工具类
+
+```
+getListViewHeightBasedOnChildren : 计算获取ListView的高度
+getGridViewVerticalSpacing : 计算GridView垂直间距
+setViewHeight : 设置View的高度
+setListViewHeightBasedOnChildren : 通过计算设置ListView的真实高度
+getDescendants : 获取父布局控件下的所有控件集合
+isTablet : 判断设备是否是平板
+getContentView : 获取activity最顶层的父布局
+```
+
+* ### CleanUtils -> 清除相关工具类
+
+```
+cleanInternalCache : 清除内部缓存
+cleanInternalFiles : 清除内部文件
+cleanInternalDbs : 清除内部数据库
+cleanInternalDbByName: 根据名称清除数据库
+cleanInternalSp : 清除内部 SP
+cleanExternalCache : 清除外部缓存
+cleanCustomCache : 清除自定义目录下的文件
+```
+
+* ### CloseUtils -> 关闭相关
+
+```
+closeIO : 关闭 IO
+closeIOQuietly: 安静关闭 IO
+```
+
+* ### FileIOUtils -> 文件输入输出流相关工具类
+
+```
+writeFileFromIS : 将输入流写入文件
+writeFileFromBytesByStream : 将字节数组写入文件
+writeFileFromBytesByChannel: 将字节数组写入文件
+writeFileFromBytesByMap : 将字节数组写入文件
+writeFileFromString : 将字符串写入文件
+readFile2List : 读取文件到字符串链表中
+readFile2String : 读取文件到字符串中
+readFile2BytesByStream : 读取文件到字节数组中
+readFile2BytesByChannel : 读取文件到字节数组中
+readFile2BytesByMap : 读取文件到字节数组中
+setBufferSize : 设置缓冲区尺寸
+```
+
+* ### FileUtils -> 文件相关工具类
+
+```
+isSDCardExist : SD卡是否存在
+getDiskCacheDir : 获取磁盘的缓存目录
+getDiskFilesDir : 获取磁盘的文件目录
+getDiskDir : 获取磁盘目录
+getFileByPath : 根据文件路径获取文件
+isFileExists : 判断文件是否存在
+rename : 重命名文件
+isDir : 判断是否是目录
+isFile : 判断是否是文件
+createOrExistsDir : 判断目录是否存在,不存在则判断是否创建成功
+createOrExistsFile : 判断文件是否存在,不存在则判断是否创建成功
+createFileByDeleteOldFile : 判断文件是否存在,存在则在创建之前删除
+copyDir : 复制目录
+copyFile : 复制文件
+moveDir : 移动目录
+moveFile : 移动文件
+deleteDir : 删除目录
+deleteFile : 删除文件
+deleteAllInDir : 删除目录下所有东西
+deleteFilesInDir : 删除目录下所有文件
+deleteFilesInDirWithFilter: 删除目录下所有过滤的文件
+listFilesInDir : 获取目录下所有文件
+listFilesInDirWithFilter : 获取目录下所有过滤的文件
+getFileLastModified : 获取文件最后修改的毫秒时间戳
+getFileCharsetSimple : 简单获取文件编码格式
+getFileLines : 获取文件行数
+getDirSize : 获取目录大小
+getFileSize : 获取文件大小
+getDirLength : 获取目录长度
+getFileLength : 获取文件长度
+getFileMD5 : 获取文件的 MD5 校验码
+getFileMD5ToString : 获取文件的 MD5 校验码
+getDirName : 根据全路径获取最长目录
+getFileName : 根据全路径获取文件名
+getFileNameNoExtension : 根据全路径获取文件名不带拓展名
+getFileExtension : 根据全路径获取文件拓展名
+changeFileExtension : 改变文件的拓展名
+```
+
+* ### ZipUtils -> 压缩相关
+
+```
+zipFiles : 批量压缩文件
+zipFile : 压缩文件
+unzipFile : 解压文件
+unzipFileByKeyword: 解压带有关键字的文件
+getFilesPath : 获取压缩文件中的文件路径链表
+getComments : 获取压缩文件中的注释链表
+```
+
+* ### JsonUtil -> json转化工具类
+
+```
+fromJson : 把 JSON 字符串 转换为 单个指定类型的对象
+toJson : 把 单个指定类型的对象 转换为 JSON 字符串
+toJSONObject : 把 单个指定类型的对象 转换为 JSONObject对象
+```
+
+* ### JSONUtils -> JSONObject解析工具类
+
+```
+getLong : 获取 JSONObject 某一long字段的值
+getInt : 获取 JSONObject 某一int字段的值
+getDouble : 获取 JSONObject 某一double字段的值
+getString : 获取 JSONObject 某一String字段的值
+getBoolean : 获取 JSONObject 某一boolean字段的值
+getStringArray : 获取 JSONObject 某一String[]字段的值
+getStringList : 获取 JSONObject 某一String集合的字段的值
+getJSONObject : 获取 JSONObject 某一JSONObject字段的值
+getJSONArray : 获取 JSONObject 某一JSONArray字段的值
+getMap : 将 JSONObject 转换为Map集合
+```
+
+* ### NetworkUtils -> 网络工具类
+
+```
+openWirelessSettings : 打开网络设置界面
+getActiveNetworkInfo : 获取活动网络信息
+isNetworkAvailable : 判断网络连接是否打开,包括移动数据连接
+isHaveInternet : 判断当前是否有网
+isGpsEnabled : Gps是否打开
+isMobile : 判断当前网络是否是移动数据网络
+isWifi : 检测当前打开的网络类型是否是WIFI
+is3G : 检测当前打开的网络类型是否是3G
+is4G : 检测当前开打的网络类型是否是4G
+isWifiEnabled : 判断 wifi 是否打开
+setWifiEnabled : 打开或关闭 wifi
+isAvailableByPing : 判断网络是否可用
+getMobileDataEnabled : 判断移动数据是否打开
+setMobileDataEnabled : 打开或关闭移动数据
+isMobileData : 判断网络是否是移动数据
+getLocalInetAddress : 遍历获取本地Ip地址
+getIPAddress : 获取 IP 地址
+getDomainAddress : 获取域名 ip 地址
+getNetStateType : 判断当前是否网络连接,返回当前网络状态的类型
+getNetworkOperatorName: 获取移动网络运营商名称
+getUrlParams : 获取URL中参数 并返回Map
+parseUrl : 解析网络请求的url
+isUrlValid : url是否有效合法
+isIP : IP地址校验
+downLoadFileByUrl : 从Url中下载文件
+```
+
+* ### ResourceUtils -> 资源工具类
+
+```
+readStringFromAssert : 读取assert下的txt文件
+openAssetsFile : 打开Assets下的文件
+openRawResource : 打开Raw下的资源
+getFileFromAssets : 获取Assets下文件的内容
+getFileFromRaw : 读取raw下文件的内容
+readInputStream : 读取输入流
+getImageFromAssetsFile : 从Assets中读取图片
+copyFilesFromAssets : 从assets目录中复制整个文件夹内容
+copyFileFromAssets : 从assets目录中复制指定文件至指定目录下
+```
+
+* ### ResUtils -> 获取res中的资源工具类
+
+```
+getResources : 获取resources对象
+getString : 获取字符串
+getDrawable : 获取资源图片
+getDimens : 获取dimes值
+getColor : 获取Color值
+getColorStateList : 获取ColorStateList值
+getDimensionPixelOffset : 获取dimes值【px不会乘以denstiy.】
+getDimensionPixelSize : 获取dimes值【getDimensionPixelSize则不管写的是dp还是sp还是px,都会乘以denstiy.】
+getStringArray : 获取字符串的数组
+getIntArray : 获取数字的数组
+getAnim : 获取动画
+isIn : 是否在数组资源中
+```
+
+* ### ThemeUtils -> 主题工具(R.attr.xx)
+
+```
+resolveColor : 解析主题的Color属性
+resolveDimension : 解析主题的Dimension属性
+resolveBoolean : 解析主题的Boolean属性
+resolveDrawable : 解析主题的Drawable属性
+resolveString : 解析主题的String属性
+```
+
+* ### Base64Utils -> Base64工具类
+
+```
+encode : Encode.(加密)
+decode : Decode.(解密)
+```
+
+* ### CipherUtils -> 加密与解密的工具类
+
+```
+md5 : MD5加密
+getDESKey : 返回可逆算法DES的密钥
+decrypt : 根据指定的密钥及算法,将字符串进行解密。
+encrypt : 根据指定的密钥及算法对指定字符串进行可逆加密
+```
+
+* ### EncodeUtils -> 编码解码相关工具类
+
+```
+urlEncode : URL 编码
+urlDecode : URL 解码
+base64Encode : Base64 编码
+base64Encode2String : Base64 编码为String
+htmlEncode : Html 编码
+htmlDecode : Html 解码
+```
+
+* ### EncryptUtils -> 加密解密相关
+
+```
+encryptMD2, encryptMD2ToString : MD2 加密
+encryptMD5, encryptMD5ToString : MD5 加密
+encryptMD5File, encryptMD5File2String : MD5 加密文件
+encryptSHA1, encryptSHA1ToString : SHA1 加密
+encryptSHA224, encryptSHA224ToString : SHA224 加密
+encryptSHA256, encryptSHA256ToString : SHA256 加密
+encryptSHA384, encryptSHA384ToString : SHA384 加密
+encryptSHA512, encryptSHA512ToString : SHA512 加密
+encryptHmacMD5, encryptHmacMD5ToString : HmacMD5 加密
+encryptHmacSHA1, encryptHmacSHA1ToString : HmacSHA1 加密
+encryptHmacSHA224, encryptHmacSHA224ToString : HmacSHA224 加密
+encryptHmacSHA256, encryptHmacSHA256ToString : HmacSHA256 加密
+encryptHmacSHA384, encryptHmacSHA384ToString : HmacSHA384 加密
+encryptHmacSHA512, encryptHmacSHA512ToString : HmacSHA512 加密
+encryptDES, encryptDES2HexString, encryptDES2Base64 : DES 加密
+decryptDES, decryptHexStringDES, decryptBase64DES : DES 解密
+encrypt3DES, encrypt3DES2HexString, encrypt3DES2Base64: 3DES 加密
+decrypt3DES, decryptHexString3DES, decryptBase64_3DES : 3DES 解密
+encryptAES, encryptAES2HexString, encryptAES2Base64 : AES 加密
+decryptAES, decryptHexStringAES, decryptBase64AES : AES 解密
+encryptRSA, encryptRSA2HexString, encryptRSA2Base64 : RSA 加密
+decryptRSA, decryptHexStringRSA, decryptBase64RSA : RSA 解密
+```
+
+* ### AppExecutors -> 应用的全局线程池 (包括单线程池的磁盘io,多线程池的网络io和主线程)
+
+```
+get : 获取线程池管理实例
+get().singleIO : 获取单线程池
+get().poolIO : 获取多线程池
+get().diskIO : 获取磁盘单线程池
+get().networkIO : 获取网络请求多线程池
+```
+
+* ### DeviceStatusUtils -> 手机状态工具类 主要包括网络、蓝牙、屏幕亮度、飞行模式、音量等
+
+```
+getScreenBrightnessModeState : 获取系统屏幕亮度模式的状态
+isScreenBrightnessModeAuto : 判断系统屏幕亮度模式是否是自动
+setScreenBrightnessMode : 设置系统屏幕亮度模式
+getScreenBrightness : 获取系统亮度
+setScreenBrightness : 设置系统亮度
+setWindowBrightness : 设置给定Activity的窗口的亮度
+setScreenBrightnessAndApply : 设置系统亮度并实时可以看到效果
+getScreenDormantTime : 获取屏幕休眠时间
+setScreenDormantTime : 设置屏幕休眠时间
+getAirplaneModeState : 获取飞行模式的状态
+isAirplaneModeOpen : 判断飞行模式是否打开
+setAirplaneMode : 设置飞行模式的状态
+getBluetoothState : 获取蓝牙的状态
+isBluetoothOpen : 判断蓝牙是否打开
+isOpenBluetooth : 是否已经开启蓝牙
+isBtAddressValid : 检验蓝牙地址的有效性
+getBluetoothDevice : 根据地址获取蓝牙设备
+isBluetoothBonded : 蓝牙是否已绑定
+setBluetooth : 设置蓝牙状态
+getRingVolume : 获取铃声音量
+setRingVolume : 获取媒体音量
+getStatusBarHeight : 计算状态栏高度高度
+```
+
+* ### DeviceUtils -> 设备相关工具类
+
+```
+getDeviceInfos : 获取设备的所有信息
+getAndroidVersionName : 获取安卓系统版本
+getSDKVersionName : 获取设备系统版本号
+getSDKVersionCode : 获取设备系统版本码
+getDeviceBrand : 获取设备品牌
+getAndroidID : 获取设备 AndroidID
+getMacAddress : 获取设备 MAC 地址
+getManufacturer : 获取设备厂商
+getHardware : 获取硬件信息
+getProduct : 获取产品信息
+getDevice : 获取设备信息
+getDisplayVersion : 获取系统版本号
+getLanguage : 获取语言
+getCountry : 获取国家
+getDeviceModel : 获取设备型号
+getMacAddress : 获取设备 MAC 地址
+isDeviceRooted : 判断设备是否 rooted
+shutdown : 关机
+reboot : 重启
+reboot2Recovery : 重启到 recovery
+reboot2Bootloader : 重启到 bootloader
+```
+
+* ### PermissionUtils -> 动态权限申请工具类
+
+```
+getPermissions : 获取应用权限
+isGranted : 判断权限是否被授予
+launchAppDetailsSettings: 打开应用具体设置
+permission : 设置请求权限
+rationale : 设置拒绝权限后再次请求的回调接口
+callback : 设置回调
+theme : 设置主题
+request : 开始请求开始请求
+```
+
+* ### KeyboardUtils -> 键盘相关工具类
+```
+showSoftInput : 动态显示软键盘
+hideSoftInput : 动态隐藏软键盘
+toggleSoftInput : 切换键盘显示与否状态
+isSoftInputVisible : 判断软键盘是否可见
+registerSoftInputChangedListener : 注册软键盘改变监听器
+unregisterSoftInputChangedListener: 注销软键盘改变监听器
+fixSoftInputLeaks : 修复软键盘内存泄漏
+onClickBlankArea2HideSoftInput : 点击屏幕空白区域隐藏软键盘
+onDisableBackKeyDown : 禁用物理返回键
+```
+
+* ### ThreadPoolUtils -> 线程池相关工具类
+
+```
+ThreadPoolUtils : ThreadPoolUtils 构造函数
+execute : 在未来某个时间执行给定的命令
+execute : 在未来某个时间执行给定的命令链表
+shutDown : 待以前提交的任务执行完毕后关闭线程池
+shutDownNow : 试图停止所有正在执行的活动任务
+isShutDown : 判断线程池是否已关闭
+isTerminated : 关闭线程池后判断所有任务是否都已完成
+awaitTermination : 请求关闭、发生超时或者当前线程中断
+submit : 提交一个 Callable 任务用于执行
+submit : 提交一个 Runnable 任务用于执行
+invokeAll, invokeAny : 执行给定的任务
+schedule : 延迟执行 Runnable 命令
+schedule : 延迟执行 Callable 命令
+scheduleWithFixedRate : 延迟并循环执行命令
+scheduleWithFixedDelay: 延迟并以固定休息时间循环执行命令
+```
+
+* ### ToastUtils -> 管理toast的类,整个app用该类来显示toast
+
+```
+toast : 显示toast在主线程中
+cancelToast : 取消toast显示
+```
\ No newline at end of file
diff --git a/app-util/build.gradle b/app-util/build.gradle
index bcbabc0..c4952b4 100644
--- a/app-util/build.gradle
+++ b/app-util/build.gradle
@@ -1,14 +1,12 @@
 apply plugin: 'com.android.library'
 
 android {
- compileSdkVersion 28
- buildToolsVersion "29.0.3"
+ compileSdkVersion build_versions.target_sdk
+ buildToolsVersion build_versions.build_tools
 
 defaultConfig {
- minSdkVersion 16
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
+ minSdkVersion build_versions.min_sdk
+ targetSdkVersion build_versions.target_sdk
 
 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 consumerProguardFiles 'consumer-rules.pro'
diff --git a/app-util/src/main/java/com/cain/util/constant/MemoryConstants.java b/app-util/src/main/java/com/cain/util/constant/MemoryConstants.java
index ddbef08..f453904 100644
--- a/app-util/src/main/java/com/cain/util/constant/MemoryConstants.java
+++ b/app-util/src/main/java/com/cain/util/constant/MemoryConstants.java
@@ -16,7 +16,8 @@
 
 package com.xuexiang.constant;
 
-import android.support.annotation.IntDef;
+
+import androidx.annotation.IntDef;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/app-util/src/main/java/com/cain/util/constant/PermissionConstants.java b/app-util/src/main/java/com/cain/util/constant/PermissionConstants.java
index 744c46e..cc4a5ac 100644
--- a/app-util/src/main/java/com/cain/util/constant/PermissionConstants.java
+++ b/app-util/src/main/java/com/cain/util/constant/PermissionConstants.java
@@ -19,7 +19,8 @@
 import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.SuppressLint;
-import android.support.annotation.StringDef;
+
+import androidx.annotation.StringDef;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/app-util/src/main/java/com/cain/util/constant/TimeConstants.java b/app-util/src/main/java/com/cain/util/constant/TimeConstants.java
index 74578e2..0efa39f 100644
--- a/app-util/src/main/java/com/cain/util/constant/TimeConstants.java
+++ b/app-util/src/main/java/com/cain/util/constant/TimeConstants.java
@@ -16,7 +16,8 @@
 
 package com.xuexiang.constant;
 
-import android.support.annotation.IntDef;
+
+import androidx.annotation.IntDef;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/app-util/src/main/java/com/cain/util/xutil/XUtil.java b/app-util/src/main/java/com/cain/util/xutil/XUtil.java
index 4d3be1f..1f6d1ac 100644
--- a/app-util/src/main/java/com/cain/util/xutil/XUtil.java
+++ b/app-util/src/main/java/com/cain/util/xutil/XUtil.java
@@ -24,14 +24,15 @@
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.annotation.RequiresPermission;
 import android.text.TextUtils;
 
-import com.xuexiang.xutil.app.ActivityLifecycleHelper;
-import com.xuexiang.xutil.app.AppUtils;
-import com.xuexiang.xutil.app.ProcessUtils;
-import com.xuexiang.xutil.app.ServiceUtils;
-import com.xuexiang.xutil.common.logger.Logger;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.app.ActivityLifecycleHelper;
+import com.cain.util.xutil.app.AppUtils;
+import com.cain.util.xutil.app.ProcessUtils;
+import com.cain.util.xutil.app.ServiceUtils;
+import com.cain.util.xutil.common.logger.Logger;
 
 import static android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/ActivityLifecycleHelper.java b/app-util/src/main/java/com/cain/util/xutil/app/ActivityLifecycleHelper.java
index 3de4340..68c079e 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/ActivityLifecycleHelper.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/ActivityLifecycleHelper.java
@@ -20,10 +20,11 @@
 import android.app.Activity;
 import android.app.Application;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
 
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.common.logger.Logger;
+import androidx.annotation.NonNull;
+
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.common.logger.Logger;
 
 import java.util.Iterator;
 import java.util.Stack;
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/ActivityUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/ActivityUtils.java
index ed12f44..7abe8c9 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/ActivityUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/ActivityUtils.java
@@ -22,11 +22,12 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.logger.Logger;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.logger.Logger;
 
 import java.util.Map;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/AppUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/AppUtils.java
index f6fc2be..6fb8db1 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/AppUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/AppUtils.java
@@ -32,18 +32,19 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RequiresPermission;
 import android.text.TextUtils;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.ShellUtils;
-import com.xuexiang.xutil.common.logger.Logger;
-import com.xuexiang.xutil.file.CleanUtils;
-import com.xuexiang.xutil.file.FileUtils;
-import com.xuexiang.xutil.security.EncryptUtils;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.ShellUtils;
+import com.cain.util.xutil.common.logger.Logger;
+import com.cain.util.xutil.file.CleanUtils;
+import com.cain.util.xutil.file.FileUtils;
+import com.cain.util.xutil.security.EncryptUtils;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/BroadcastUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/BroadcastUtils.java
index 6536cd5..d31c42a 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/BroadcastUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/BroadcastUtils.java
@@ -21,9 +21,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
 
-import com.xuexiang.xutil.XUtil;
+import androidx.annotation.NonNull;
+
+import com.cain.util.xutil.XUtil;
 
 import java.util.List;
 import java.util.Map;
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/IntentUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/IntentUtils.java
index 613bf99..d42e11a 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/IntentUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/IntentUtils.java
@@ -24,13 +24,14 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.provider.MediaStore;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringDef;
-import android.support.v4.content.FileProvider;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.file.FileUtils;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringDef;
+import androidx.core.content.FileProvider;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.file.FileUtils;
 
 import java.io.File;
 import java.io.Serializable;
@@ -39,11 +40,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import static com.xuexiang.xutil.app.IntentUtils.DocumentType.ANY;
-import static com.xuexiang.xutil.app.IntentUtils.DocumentType.AUDIO;
-import static com.xuexiang.xutil.app.IntentUtils.DocumentType.IMAGE;
-import static com.xuexiang.xutil.app.IntentUtils.DocumentType.VIDEO;
-
 /**
 * 
 * desc : 意图相关工具类
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/PathUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/PathUtils.java
index 19a7fef..110bfd8 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/PathUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/PathUtils.java
@@ -28,14 +28,15 @@
 import android.os.storage.StorageManager;
 import android.provider.DocumentsContract;
 import android.provider.MediaStore;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.content.FileProvider;
 import android.text.TextUtils;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.common.logger.Logger;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.content.FileProvider;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.common.logger.Logger;
 
 import java.io.File;
 import java.lang.reflect.Array;
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/ProcessUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/ProcessUtils.java
index 44f5a39..2fa6796 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/ProcessUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/ProcessUtils.java
@@ -30,12 +30,13 @@
 import android.os.Build;
 import android.os.Process;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RequiresPermission;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.logger.Logger;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.logger.Logger;
 
 import java.util.Arrays;
 import java.util.Collections;
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/SAFUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/SAFUtils.java
index 2f36046..82dd3b7 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/SAFUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/SAFUtils.java
@@ -26,15 +26,16 @@
 import android.os.ParcelFileDescriptor;
 import android.provider.DocumentsContract;
 import android.provider.MediaStore;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.StringDef;
 
+import androidx.annotation.RequiresApi;
+import androidx.annotation.StringDef;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.logger.Logger;
+import com.cain.util.xutil.display.ImageUtils;
+import com.cain.util.xutil.file.FileIOUtils;
+import com.cain.util.xutil.file.FileUtils;
 import com.xuexiang.constant.MimeTypeConstants;
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.logger.Logger;
-import com.xuexiang.xutil.display.ImageUtils;
-import com.xuexiang.xutil.file.FileIOUtils;
-import com.xuexiang.xutil.file.FileUtils;
 
 import java.io.File;
 import java.io.FileNotFoundException;
diff --git a/app-util/src/main/java/com/cain/util/xutil/app/ServiceUtils.java b/app-util/src/main/java/com/cain/util/xutil/app/ServiceUtils.java
index 6f213a8..e60661e 100644
--- a/app-util/src/main/java/com/cain/util/xutil/app/ServiceUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/app/ServiceUtils.java
@@ -22,8 +22,8 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.logger.Logger;
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.logger.Logger;
 
 import java.util.Collections;
 import java.util.HashSet;
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/ClickUtils.java b/app-util/src/main/java/com/cain/util/xutil/common/ClickUtils.java
index 73f0405..af11533 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/ClickUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/ClickUtils.java
@@ -19,8 +19,8 @@
 import android.os.SystemClock;
 import android.view.View;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.tip.ToastUtils;
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.tip.ToastUtils;
 
 import java.util.Timer;
 import java.util.TimerTask;
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/CollectionUtils.java b/app-util/src/main/java/com/cain/util/xutil/common/CollectionUtils.java
index 3182a37..abfd56e 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/CollectionUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/CollectionUtils.java
@@ -16,8 +16,9 @@
 
 package com.cain.util.xutil.common;
 
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/MapUtils.java b/app-util/src/main/java/com/cain/util/xutil/common/MapUtils.java
index 1862eea..b2aed15 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/MapUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/MapUtils.java
@@ -16,8 +16,9 @@
 
 package com.cain.util.xutil.common;
 
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.util.Iterator;
 import java.util.LinkedHashMap;
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/ObjectUtils.java b/app-util/src/main/java/com/cain/util/xutil/common/ObjectUtils.java
index a0a66b1..e02e415 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/ObjectUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/ObjectUtils.java
@@ -17,14 +17,15 @@
 package com.cain.util.xutil.common;
 
 import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.support.v4.util.LongSparseArray;
-import android.support.v4.util.SimpleArrayMap;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 
+import androidx.annotation.RequiresApi;
+import androidx.collection.LongSparseArray;
+import androidx.collection.SimpleArrayMap;
+
 import java.lang.reflect.Array;
 import java.util.Collection;
 import java.util.Map;
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/StringUtils.java b/app-util/src/main/java/com/cain/util/xutil/common/StringUtils.java
index 0a04376..53f8564 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/StringUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/StringUtils.java
@@ -16,7 +16,8 @@
 
 package com.cain.util.xutil.common;
 
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/logger/LogcatLogger.java b/app-util/src/main/java/com/cain/util/xutil/common/logger/LogcatLogger.java
index 82205be..3613175 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/logger/LogcatLogger.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/logger/LogcatLogger.java
@@ -16,9 +16,10 @@
 
 package com.cain.util.xutil.common.logger;
 
-import android.support.annotation.NonNull;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/common/logger/Logger.java b/app-util/src/main/java/com/cain/util/xutil/common/logger/Logger.java
index 1641d9f..945f452 100644
--- a/app-util/src/main/java/com/cain/util/xutil/common/logger/Logger.java
+++ b/app-util/src/main/java/com/cain/util/xutil/common/logger/Logger.java
@@ -16,10 +16,11 @@
 
 package com.cain.util.xutil.common.logger;
 
-import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+
 /**
 * 
 * desc : Logger日志记录
diff --git a/app-util/src/main/java/com/cain/util/xutil/data/ACache.java b/app-util/src/main/java/com/cain/util/xutil/data/ACache.java
index 5c84d2d..7d1d0f5 100644
--- a/app-util/src/main/java/com/cain/util/xutil/data/ACache.java
+++ b/app-util/src/main/java/com/cain/util/xutil/data/ACache.java
@@ -25,11 +25,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
-import android.support.annotation.NonNull;
-import android.support.v4.util.SimpleArrayMap;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.file.CloseUtils;
+import androidx.annotation.NonNull;
+import androidx.collection.SimpleArrayMap;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.file.CloseUtils;
 
 import org.json.JSONArray;
 import org.json.JSONObject;
diff --git a/app-util/src/main/java/com/cain/util/xutil/data/BaseSPUtil.java b/app-util/src/main/java/com/cain/util/xutil/data/BaseSPUtil.java
index c5a72ac..a55b234 100644
--- a/app-util/src/main/java/com/cain/util/xutil/data/BaseSPUtil.java
+++ b/app-util/src/main/java/com/cain/util/xutil/data/BaseSPUtil.java
@@ -20,9 +20,9 @@
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
 
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.net.JsonUtil;
-import com.xuexiang.xutil.security.Base64Utils;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.net.JsonUtil;
+import com.cain.util.xutil.security.Base64Utils;
 
 import java.lang.reflect.Type;
 import java.util.Map;
diff --git a/app-util/src/main/java/com/cain/util/xutil/data/CloneUtils.java b/app-util/src/main/java/com/cain/util/xutil/data/CloneUtils.java
index 7b4f9df..4529b87 100644
--- a/app-util/src/main/java/com/cain/util/xutil/data/CloneUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/data/CloneUtils.java
@@ -16,7 +16,8 @@
 
 package com.cain.util.xutil.data;
 
-import com.xuexiang.xutil.file.CloseUtils;
+
+import com.cain.util.xutil.file.CloseUtils;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/app-util/src/main/java/com/cain/util/xutil/data/ConvertTools.java b/app-util/src/main/java/com/cain/util/xutil/data/ConvertTools.java
index 64bedc2..112cb83 100644
--- a/app-util/src/main/java/com/cain/util/xutil/data/ConvertTools.java
+++ b/app-util/src/main/java/com/cain/util/xutil/data/ConvertTools.java
@@ -16,7 +16,8 @@
 
 package com.cain.util.xutil.data;
 
-import com.xuexiang.xutil.common.StringUtils;
+
+import com.cain.util.xutil.common.StringUtils;
 
 import java.util.Locale;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/data/DateUtils.java b/app-util/src/main/java/com/cain/util/xutil/data/DateUtils.java
index cc9a0d2..5acee16 100644
--- a/app-util/src/main/java/com/cain/util/xutil/data/DateUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/data/DateUtils.java
@@ -17,11 +17,12 @@
 package com.cain.util.xutil.data;
 
 import android.annotation.SuppressLint;
-import android.support.annotation.Nullable;
 
+import androidx.annotation.Nullable;
+
+import com.cain.util.xutil.common.StringUtils;
 import com.xuexiang.constant.DateFormatConstants;
 import com.xuexiang.constant.TimeConstants;
-import com.xuexiang.xutil.common.StringUtils;
 
 import java.text.DateFormat;
 import java.text.ParseException;
@@ -32,9 +33,9 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static com.cain.util.xutil.common.StringUtils.EMPTY;
 import static com.xuexiang.constant.TimeConstants.MIN;
 import static com.xuexiang.constant.TimeConstants.SEC;
-import static com.xuexiang.xutil.common.StringUtils.EMPTY;
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/data/SPUtils.java b/app-util/src/main/java/com/cain/util/xutil/data/SPUtils.java
index ca03524..b590cb2 100644
--- a/app-util/src/main/java/com/cain/util/xutil/data/SPUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/data/SPUtils.java
@@ -20,10 +20,10 @@
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.net.JsonUtil;
-import com.xuexiang.xutil.security.Base64Utils;
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.net.JsonUtil;
+import com.cain.util.xutil.security.Base64Utils;
 
 import java.lang.reflect.Type;
 import java.util.Map;
diff --git a/app-util/src/main/java/com/cain/util/xutil/display/BarUtils.java b/app-util/src/main/java/com/cain/util/xutil/display/BarUtils.java
index b299399..fc3b17d 100644
--- a/app-util/src/main/java/com/cain/util/xutil/display/BarUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/display/BarUtils.java
@@ -22,10 +22,6 @@
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.v4.widget.DrawerLayout;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
@@ -34,7 +30,13 @@
 import android.view.WindowManager;
 import android.widget.LinearLayout;
 
-import com.xuexiang.xutil.XUtil;
+import androidx.annotation.ColorInt;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.drawerlayout.widget.DrawerLayout;
+
+import com.cain.util.xutil.XUtil;
+
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/display/ColorUtils.java b/app-util/src/main/java/com/cain/util/xutil/display/ColorUtils.java
index 42da441..4a2d5f2 100644
--- a/app-util/src/main/java/com/cain/util/xutil/display/ColorUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/display/ColorUtils.java
@@ -18,11 +18,12 @@
 
 import android.content.res.ColorStateList;
 import android.graphics.Color;
-import android.support.annotation.ColorInt;
-import android.support.annotation.ColorRes;
-import android.support.annotation.NonNull;
 
-import com.xuexiang.xutil.resource.ResUtils;
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+import androidx.annotation.NonNull;
+
+import com.cain.util.xutil.resource.ResUtils;
 
 import java.util.Random;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/display/DensityUtils.java b/app-util/src/main/java/com/cain/util/xutil/display/DensityUtils.java
index 73fdb50..d680069 100755
--- a/app-util/src/main/java/com/cain/util/xutil/display/DensityUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/display/DensityUtils.java
@@ -22,7 +22,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.xuexiang.xutil.XUtil;
+import com.cain.util.xutil.XUtil;
+
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/display/ImageUtils.java b/app-util/src/main/java/com/cain/util/xutil/display/ImageUtils.java
index 71991fe..02b897b 100644
--- a/app-util/src/main/java/com/cain/util/xutil/display/ImageUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/display/ImageUtils.java
@@ -43,19 +43,20 @@
 import android.renderscript.Element;
 import android.renderscript.RenderScript;
 import android.renderscript.ScriptIntrinsicBlur;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.support.v4.content.ContextCompat;
 import android.view.View;
 import android.widget.ImageView;
 
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.core.content.ContextCompat;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.file.CloseUtils;
 import com.xuexiang.constant.MemoryConstants;
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.file.CloseUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/app-util/src/main/java/com/cain/util/xutil/display/ScreenUtils.java b/app-util/src/main/java/com/cain/util/xutil/display/ScreenUtils.java
index a3996f3..fa12a6c 100644
--- a/app-util/src/main/java/com/cain/util/xutil/display/ScreenUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/display/ScreenUtils.java
@@ -26,17 +26,19 @@
 import android.graphics.Point;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
 import android.util.DisplayMetrics;
 import android.view.Surface;
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.logger.Logger;
-import com.xuexiang.xutil.resource.ResUtils;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.logger.Logger;
+import com.cain.util.xutil.resource.ResUtils;
+
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/display/ViewUtils.java b/app-util/src/main/java/com/cain/util/xutil/display/ViewUtils.java
index faf234f..ff4d3fe 100644
--- a/app-util/src/main/java/com/cain/util/xutil/display/ViewUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/display/ViewUtils.java
@@ -26,12 +26,6 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Build;
-import android.support.annotation.ColorRes;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.StringRes;
-import android.support.v4.content.ContextCompat;
 import android.view.TouchDelegate;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -48,6 +42,13 @@
 import android.widget.RelativeLayout.LayoutParams;
 import android.widget.TextView;
 
+import androidx.annotation.ColorRes;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.StringRes;
+import androidx.core.content.ContextCompat;
+
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/file/CleanUtils.java b/app-util/src/main/java/com/cain/util/xutil/file/CleanUtils.java
index 65fbe02..7ac06d7 100644
--- a/app-util/src/main/java/com/cain/util/xutil/file/CleanUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/file/CleanUtils.java
@@ -18,8 +18,8 @@
 
 import android.os.Environment;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.StringUtils;
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.StringUtils;
 
 import java.io.File;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/file/FileUtils.java b/app-util/src/main/java/com/cain/util/xutil/file/FileUtils.java
index fd5678a..752befd 100644
--- a/app-util/src/main/java/com/cain/util/xutil/file/FileUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/file/FileUtils.java
@@ -24,12 +24,13 @@
 import android.os.Build;
 import android.os.Environment;
 import android.os.StatFs;
-import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.app.PathUtils;
-import com.xuexiang.xutil.app.SAFUtils;
+import androidx.annotation.Nullable;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.app.PathUtils;
+import com.cain.util.xutil.app.SAFUtils;
 
 import java.io.BufferedInputStream;
 import java.io.File;
diff --git a/app-util/src/main/java/com/cain/util/xutil/net/JSONUtils.java b/app-util/src/main/java/com/cain/util/xutil/net/JSONUtils.java
index d31a02a..6f79068 100644
--- a/app-util/src/main/java/com/cain/util/xutil/net/JSONUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/net/JSONUtils.java
@@ -15,13 +15,18 @@
 */
 package com.cain.util.xutil.net;
 
-import com.xuexiang.xutil.common.StringUtils;
+
+import com.cain.util.xutil.common.StringUtils;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/net/NetworkUtils.java b/app-util/src/main/java/com/cain/util/xutil/net/NetworkUtils.java
index 155ad01..1596f51 100644
--- a/app-util/src/main/java/com/cain/util/xutil/net/NetworkUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/net/NetworkUtils.java
@@ -22,16 +22,18 @@
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
 import android.net.wifi.WifiManager;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresPermission;
+import android.os.Build;
 import android.telephony.TelephonyManager;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.common.ShellUtils;
-import com.xuexiang.xutil.common.logger.Logger;
-import com.xuexiang.xutil.file.CloseUtils;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.common.ShellUtils;
+import com.cain.util.xutil.common.logger.Logger;
+import com.cain.util.xutil.file.CloseUtils;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -69,7 +71,6 @@
 * 
*/ public final class NetworkUtils { - /** * Don't let anyone instantiate this class. */ @@ -118,7 +119,7 @@ public static boolean isNetworkAvailable() { NetworkInfo[] info = manager.getAllNetworkInfo(); if (info != null) { for (NetworkInfo anInfo : info) { - if (anInfo.getState() == State.CONNECTED) { + if (anInfo.getState() == NetworkInfo.State.CONNECTED) { netState = true; break; } @@ -143,7 +144,7 @@ public static boolean isHaveInternet() { if (connectivity != null) { NetworkInfo info = connectivity.getActiveNetworkInfo(); if (info != null && info.isConnected()) { - if (info.getState() == State.CONNECTED) { + if (info.getState() == NetworkInfo.State.CONNECTED) { return true; } } @@ -465,6 +466,7 @@ private static byte byteOfInt(int value, int which) { * @param useIPv4 True to use ipv4, false otherwise. * @return the ip address */ + @RequiresApi(api = Build.VERSION_CODES.GINGERBREAD) @RequiresPermission(INTERNET) public static String getIPAddress(final boolean useIPv4) { try { @@ -473,8 +475,10 @@ public static String getIPAddress(final boolean useIPv4) { while (nis.hasMoreElements()) { NetworkInterface ni = nis.nextElement(); // To prevent phone of xiaomi return "10.0.2.15" - if (!ni.isUp() || ni.isLoopback()) { - continue; + if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.GINGERBREAD) { + if (!ni.isUp() || ni.isLoopback()) { + continue; + } } Enumeration addresses = ni.getInetAddresses(); while (addresses.hasMoreElements()) { @@ -600,13 +604,13 @@ public enum NetState { * * @return type of network *
    - *
  • {@link NetState#NET_WIFI }
  • - *
  • {@link NetState#NET_5G }
  • - *
  • {@link NetState#NET_4G }
  • - *
  • {@link NetState#NET_3G }
  • - *
  • {@link NetState#NET_2G }
  • - *
  • {@link NetState#NET_UNKNOWN}
  • - *
  • {@link NetState#NET_NO }
  • + *
  • {@link NetworkUtils.NetState#NET_WIFI }
  • + *
  • {@link NetworkUtils.NetState#NET_5G }
  • + *
  • {@link NetworkUtils.NetState#NET_4G }
  • + *
  • {@link NetworkUtils.NetState#NET_3G }
  • + *
  • {@link NetworkUtils.NetState#NET_2G }
  • + *
  • {@link NetworkUtils.NetState#NET_UNKNOWN}
  • + *
  • {@link NetworkUtils.NetState#NET_NO }
  • *
*/ @RequiresPermission(ACCESS_NETWORK_STATE) @@ -680,11 +684,11 @@ private static boolean isEthernet() { if (info == null) { return false; } - State state = info.getState(); + NetworkInfo.State state = info.getState(); if (null == state) { return false; } - return state == State.CONNECTED || state == State.CONNECTING; + return state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING; } /** diff --git a/app-util/src/main/java/com/cain/util/xutil/resource/ResUtils.java b/app-util/src/main/java/com/cain/util/xutil/resource/ResUtils.java index 6234376..8197732 100755 --- a/app-util/src/main/java/com/cain/util/xutil/resource/ResUtils.java +++ b/app-util/src/main/java/com/cain/util/xutil/resource/ResUtils.java @@ -21,21 +21,23 @@ import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.AnimRes; -import android.support.annotation.ArrayRes; -import android.support.annotation.ColorRes; -import android.support.annotation.DimenRes; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.annotation.StyleableRes; -import android.support.v7.content.res.AppCompatResources; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; -import com.xuexiang.xutil.XUtil; +import androidx.annotation.AnimRes; +import androidx.annotation.ArrayRes; +import androidx.annotation.ColorRes; +import androidx.annotation.DimenRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.annotation.StyleableRes; +import androidx.appcompat.content.res.AppCompatResources; + +import com.cain.util.xutil.XUtil; + /** *
diff --git a/app-util/src/main/java/com/cain/util/xutil/resource/ResourceUtils.java b/app-util/src/main/java/com/cain/util/xutil/resource/ResourceUtils.java
index a2f146b..887b431 100644
--- a/app-util/src/main/java/com/cain/util/xutil/resource/ResourceUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/resource/ResourceUtils.java
@@ -19,14 +19,15 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
 
-import com.xuexiang.xutil.common.StringUtils;
-import com.xuexiang.xutil.common.logger.Logger;
-import com.xuexiang.xutil.display.ImageUtils;
-import com.xuexiang.xutil.file.CloseUtils;
-import com.xuexiang.xutil.file.FileIOUtils;
-import com.xuexiang.xutil.file.FileUtils;
+import androidx.annotation.Nullable;
+
+import com.cain.util.xutil.common.StringUtils;
+import com.cain.util.xutil.common.logger.Logger;
+import com.cain.util.xutil.display.ImageUtils;
+import com.cain.util.xutil.file.CloseUtils;
+import com.cain.util.xutil.file.FileIOUtils;
+import com.cain.util.xutil.file.FileUtils;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -34,7 +35,8 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 
-import static com.xuexiang.xutil.common.StringUtils.EMPTY;
+import static com.cain.util.xutil.common.StringUtils.EMPTY;
+
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/resource/ThemeUtils.java b/app-util/src/main/java/com/cain/util/xutil/resource/ThemeUtils.java
index 914409f..e680cc5 100755
--- a/app-util/src/main/java/com/cain/util/xutil/resource/ThemeUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/resource/ThemeUtils.java
@@ -23,14 +23,16 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.support.annotation.ArrayRes;
-import android.support.annotation.AttrRes;
-import android.support.annotation.ColorInt;
-import android.support.annotation.ColorRes;
-import android.support.annotation.NonNull;
 import android.util.TypedValue;
 
-import com.xuexiang.xutil.display.ColorUtils;
+import androidx.annotation.ArrayRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+import androidx.annotation.NonNull;
+
+import com.cain.util.xutil.display.ColorUtils;
+
 
 /**
 * 
diff --git a/app-util/src/main/java/com/cain/util/xutil/security/CipherUtils.java b/app-util/src/main/java/com/cain/util/xutil/security/CipherUtils.java
index a1f9616..e784dd4 100644
--- a/app-util/src/main/java/com/cain/util/xutil/security/CipherUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/security/CipherUtils.java
@@ -15,7 +15,8 @@
 */
 package com.cain.util.xutil.security;
 
-import com.xuexiang.xutil.data.ConvertTools;
+
+import com.cain.util.xutil.data.ConvertTools;
 
 import java.io.UnsupportedEncodingException;
 import java.security.Key;
diff --git a/app-util/src/main/java/com/cain/util/xutil/security/EncryptUtils.java b/app-util/src/main/java/com/cain/util/xutil/security/EncryptUtils.java
index 5e27a14..5dea6d5 100644
--- a/app-util/src/main/java/com/cain/util/xutil/security/EncryptUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/security/EncryptUtils.java
@@ -18,7 +18,7 @@
 
 import android.util.Base64;
 
-import com.xuexiang.xutil.file.CloseUtils;
+import com.cain.util.xutil.file.CloseUtils;
 
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/app-util/src/main/java/com/cain/util/xutil/system/AppExecutors.java b/app-util/src/main/java/com/cain/util/xutil/system/AppExecutors.java
index 920b4ff..0e37306 100644
--- a/app-util/src/main/java/com/cain/util/xutil/system/AppExecutors.java
+++ b/app-util/src/main/java/com/cain/util/xutil/system/AppExecutors.java
@@ -18,7 +18,8 @@
 
 import android.os.Handler;
 import android.os.Looper;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
diff --git a/app-util/src/main/java/com/cain/util/xutil/system/DeviceUtils.java b/app-util/src/main/java/com/cain/util/xutil/system/DeviceUtils.java
index 18c862d..d2e7dc1 100644
--- a/app-util/src/main/java/com/cain/util/xutil/system/DeviceUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/system/DeviceUtils.java
@@ -26,13 +26,14 @@
 import android.os.Build;
 import android.os.PowerManager;
 import android.provider.Settings;
-import android.support.annotation.RequiresPermission;
 import android.telephony.TelephonyManager;
 
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.app.AppUtils;
-import com.xuexiang.xutil.common.ShellUtils;
-import com.xuexiang.xutil.common.StringUtils;
+import androidx.annotation.RequiresPermission;
+
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.app.AppUtils;
+import com.cain.util.xutil.common.ShellUtils;
+import com.cain.util.xutil.common.StringUtils;
 
 import java.io.File;
 import java.lang.reflect.Field;
diff --git a/app-util/src/main/java/com/cain/util/xutil/system/KeyboardUtils.java b/app-util/src/main/java/com/cain/util/xutil/system/KeyboardUtils.java
index c942824..a425f43 100644
--- a/app-util/src/main/java/com/cain/util/xutil/system/KeyboardUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/system/KeyboardUtils.java
@@ -32,7 +32,7 @@
 import android.widget.EditText;
 import android.widget.FrameLayout;
 
-import com.xuexiang.xutil.XUtil;
+import com.cain.util.xutil.XUtil;
 
 import java.lang.reflect.Field;
 
diff --git a/app-util/src/main/java/com/cain/util/xutil/system/ThreadPoolUtils.java b/app-util/src/main/java/com/cain/util/xutil/system/ThreadPoolUtils.java
index 2d322fc..f2cb93e 100644
--- a/app-util/src/main/java/com/cain/util/xutil/system/ThreadPoolUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/system/ThreadPoolUtils.java
@@ -17,7 +17,8 @@
 package com.cain.util.xutil.system;
 
 import android.os.Looper;
-import android.support.annotation.IntDef;
+
+import androidx.annotation.IntDef;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/app-util/src/main/java/com/cain/util/xutil/tip/ToastUtils.java b/app-util/src/main/java/com/cain/util/xutil/tip/ToastUtils.java
index 13e9d1f..b647c62 100644
--- a/app-util/src/main/java/com/cain/util/xutil/tip/ToastUtils.java
+++ b/app-util/src/main/java/com/cain/util/xutil/tip/ToastUtils.java
@@ -22,9 +22,10 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.xuexiang.xutil.R;
-import com.xuexiang.xutil.XUtil;
-import com.xuexiang.xutil.resource.ResUtils;
+import com.cain.util.R;
+import com.cain.util.xutil.XUtil;
+import com.cain.util.xutil.resource.ResUtils;
+
 
 /**
 * 
diff --git a/app-util/src/main/res/drawable/xutil_bg_black_circular_10.xml b/app-util/src/main/res/drawable/xutil_bg_black_circular_10.xml
new file mode 100644
index 0000000..e30edc6
--- /dev/null
+++ b/app-util/src/main/res/drawable/xutil_bg_black_circular_10.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 
+ 
+
diff --git a/app-util/src/main/res/layout-large/xutil_layout_toast.xml b/app-util/src/main/res/layout-large/xutil_layout_toast.xml
new file mode 100644
index 0000000..a427d8d
--- /dev/null
+++ b/app-util/src/main/res/layout-large/xutil_layout_toast.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ 
+
+
\ No newline at end of file
diff --git a/app-util/src/main/res/layout-xlarge/xutil_layout_toast.xml b/app-util/src/main/res/layout-xlarge/xutil_layout_toast.xml
new file mode 100644
index 0000000..d29b47a
--- /dev/null
+++ b/app-util/src/main/res/layout-xlarge/xutil_layout_toast.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ 
+
+
\ No newline at end of file
diff --git a/app-util/src/main/res/layout/xutil_layout_toast.xml b/app-util/src/main/res/layout/xutil_layout_toast.xml
new file mode 100644
index 0000000..922c4f3
--- /dev/null
+++ b/app-util/src/main/res/layout/xutil_layout_toast.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ 
+
+
\ No newline at end of file
diff --git a/app-util/src/main/res/values-v21/xutil_styles.xml b/app-util/src/main/res/values-v21/xutil_styles.xml
new file mode 100644
index 0000000..1f8877a
--- /dev/null
+++ b/app-util/src/main/res/values-v21/xutil_styles.xml
@@ -0,0 +1,16 @@
+
+
+
+ 
+
\ No newline at end of file
diff --git a/app-util/src/main/res/values/xutil_styles.xml b/app-util/src/main/res/values/xutil_styles.xml
new file mode 100644
index 0000000..f98ff26
--- /dev/null
+++ b/app-util/src/main/res/values/xutil_styles.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ 
+
\ No newline at end of file
diff --git a/app-util/src/main/res/xml/xutil_provider_paths.xml b/app-util/src/main/res/xml/xutil_provider_paths.xml
new file mode 100644
index 0000000..0c40bb3
--- /dev/null
+++ b/app-util/src/main/res/xml/xutil_provider_paths.xml
@@ -0,0 +1,26 @@
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ee7ee64..32cd9d3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,26 +3,84 @@
 xmlns:tools="http://schemas.android.com/tools"
 package="com.cain.ui">
 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
 
 
->
+ 
 
- 
-
- 
+ 
 
 
-
 
 
+
 
+
+
+ 
+ 
+
+ 
+
+ 
+
+
+ 
+
+
+ 
+
+
 
 
 
\ No newline at end of file
diff --git a/app/src/main/java/com/cain/ui/MainActivity.java b/app/src/main/java/com/cain/ui/MainActivity.java
index 3b7f22d..597e5b4 100644
--- a/app/src/main/java/com/cain/ui/MainActivity.java
+++ b/app/src/main/java/com/cain/ui/MainActivity.java
@@ -4,14 +4,23 @@
 import android.os.Bundle;
 import android.widget.LinearLayout;
 
-import com.cain.base.base.BaseActivity;
+import com.cain.ui.base.BaseUIActivity;
 import com.cain.ui.fragment.ComponentsFragment;
+import com.cain.ui.fragment.ExpandsFragment;
+import com.cain.ui.fragment.UtilitysFragment;
+import com.cain.util.sub.app.FragmentUtils;
 import com.google.android.material.tabs.TabLayout;
 
 import butterknife.BindView;
 
 
-public class MainActivity extends BaseActivity {
+public class MainActivity extends BaseUIActivity {
+
+ private static final int POS_COMPONENTS = 0;
+ private static final int POS_UTILITYS = 1;
+ private static final int POS_EXPANDS = 2;
+ private static final int POS_ABOUT = 3;
+ private static final int POS_LOGOUT = 5;
 
 private LinearLayout mLLMenu;
 private String[] mMenuTitles;
@@ -56,25 +65,29 @@ private void initTab() {
 expand.setIcon(R.drawable.selector_icon_tabbar_expand);
 mTabLayout.addTab(expand);
 
- switchPage(ComponentsFragment.class);
+
+ ComponentsFragment componentsFragment = new ComponentsFragment();
+ UtilitysFragment utilitysFragment = new UtilitysFragment();
+ ExpandsFragment expandsFragment = new ExpandsFragment();
+
+ FragmentUtils.add(getSupportFragmentManager(),componentsFragment,R.id.fragment_container);
 
 mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
 @Override
 public void onTabSelected(TabLayout.Tab tab) {
- /* mAdapter.setSelected(tab.getPosition());
 switch (tab.getPosition()) {
 case POS_COMPONENTS:
- switchPage(ComponentsFragment.class);
+ FragmentUtils.replace(getSupportFragmentManager(),componentsFragment,R.id.fragment_container);
 break;
 case 1:
- switchPage(UtilitysFragment.class);
+ FragmentUtils.replace(getSupportFragmentManager(),utilitysFragment,R.id.fragment_container);
 break;
 case 2:
- switchPage(ExpandsFragment.class);
+ FragmentUtils.replace(getSupportFragmentManager(),expandsFragment,R.id.fragment_container);
 break;
 default:
 break;
- }*/
+ }
 }
 
 @Override
diff --git a/app/src/main/java/com/cain/ui/MyApp.java b/app/src/main/java/com/cain/ui/MyApp.java
new file mode 100644
index 0000000..97f9f90
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/MyApp.java
@@ -0,0 +1,69 @@
+package com.cain.ui;
+
+import android.app.Application;
+import android.content.Context;
+
+import com.cain.base.base.BaseActivity;
+import com.cain.cpage.AppPageConfig;
+import com.cain.cpage.PageConfig;
+import com.xuexiang.xui.XUI;
+
+
+/**
+ * 应用初始化
+ * @since 2018年11月7日 下午1:12
+ */
+public class MyApp extends Application {
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ //解决4.x运行崩溃的问题
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ initUI();
+ //初始化基础库
+ //三方SDK初始化
+ //运营统计数据运行时不初始化
+
+ }
+
+ /**
+ * 初始化XUI 框架
+ */
+ private void initUI() {
+ XUI.init(this);
+ XUI.debug(MyApp.isDebug());
+// //设置默认字体为华文行楷
+// XUI.getInstance().initFontStyle("fonts/hwxk.ttf");
+
+ initPage(this);
+ }
+
+
+ /**
+ * 初始化XPage页面框架
+ *
+ * @param application
+ */
+ private static void initPage(Application application) {
+ //自动注册页面
+ PageConfig.getInstance()
+ .setPageConfiguration(context -> {
+ //自动注册页面,是编译时自动生成的,build一下就出来了
+ return AppPageConfig.getInstance().getPages();
+ })
+ .debug(MyApp.isDebug() ? "PageLog" : null)
+ .setContainActivityClazz(BaseActivity.class)
+ .enableWatcher(MyApp.isDebug())
+ .init(application);
+ }
+
+ public static boolean isDebug() {
+ return BuildConfig.DEBUG;
+ }
+
+}
diff --git a/app/src/main/java/com/cain/ui/activity/ComponentsActivity.java b/app/src/main/java/com/cain/ui/activity/ComponentsActivity.java
new file mode 100644
index 0000000..6f1759b
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/activity/ComponentsActivity.java
@@ -0,0 +1,47 @@
+package com.cain.ui.activity;
+
+import android.os.Bundle;
+
+import com.cain.ui.R;
+import com.cain.ui.base.BaseUIActivity;
+import com.cain.ui.fragment.components.circle.CircleIndexFragment;
+import com.cain.ui.fragment.components.circle.CountProgressFragment;
+import com.cain.util.sub.app.FragmentUtils;
+
+public class ComponentsActivity extends BaseUIActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initViews();
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_components;
+ }
+
+ private void initViews() {
+ int item_index = getIntent().getIntExtra("item_index", 0);
+
+ switch (item_index) {
+ case 0:
+ CircleIndexFragment fragment = new CircleIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment,R.id.fragment_container_components);
+ break;
+ case 1:
+ CountProgressFragment countProgressFragment = new CountProgressFragment();
+ FragmentUtils.add(getSupportFragmentManager(),countProgressFragment,R.id.fragment_container_components);
+ break;
+ case 2:
+ CircleIndexFragment fragment1 = new CircleIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment1,R.id.fragment_container_components);
+ break;
+ default:
+ CircleIndexFragment fragment2 = new CircleIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment2,R.id.fragment_container_components);
+ break;
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/cain/ui/activity/ExpandsActivity.java b/app/src/main/java/com/cain/ui/activity/ExpandsActivity.java
new file mode 100644
index 0000000..beb6fa0
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/activity/ExpandsActivity.java
@@ -0,0 +1,50 @@
+package com.cain.ui.activity;
+
+import android.os.Bundle;
+
+import com.cain.ui.R;
+import com.cain.ui.base.BaseUIActivity;
+import com.cain.ui.fragment.components.circle.CircleIndexFragment;
+import com.cain.ui.fragment.writestyle.WritesIndexFragment;
+import com.cain.util.sub.app.FragmentUtils;
+
+/**
+ * 拓展 实验模块 的 容器
+ */
+public class ExpandsActivity extends BaseUIActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initViews();
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_expands;
+ }
+
+ private void initViews() {
+ int item_index = getIntent().getIntExtra("item_index", 0);
+
+ switch (item_index) {
+ case 0:
+ WritesIndexFragment fragment = new WritesIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment,R.id.fragment_container_expands);
+ break;
+ case 1:
+ WritesIndexFragment countProgressFragment = new WritesIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),countProgressFragment,R.id.fragment_container_expands);
+ break;
+ case 2:
+ CircleIndexFragment fragment1 = new CircleIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment1,R.id.fragment_container_expands);
+ break;
+ default:
+ CircleIndexFragment fragment2 = new CircleIndexFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment2,R.id.fragment_container_expands);
+ break;
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/cain/ui/activity/PermissionTestActivity.java b/app/src/main/java/com/cain/ui/activity/PermissionTestActivity.java
new file mode 100644
index 0000000..661eaa3
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/activity/PermissionTestActivity.java
@@ -0,0 +1,230 @@
+package com.cain.ui.activity;
+
+import android.Manifest;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.cain.ui.R;
+import com.cain.ui.base.BaseUIActivity;
+import com.xuexiang.xui.widget.toast.XToast;
+import com.zyq.easypermission.EasyPermission;
+import com.zyq.easypermission.EasyPermissionResult;
+
+import java.util.List;
+
+import butterknife.BindView;
+
+public class PermissionTestActivity extends BaseUIActivity {
+
+ private static final int RC_CODE_CALLPHONE = 1024;
+
+ @BindView(R.id.btn_permission_1)
+ Button btn1;
+
+ @BindView(R.id.btn_permission_2)
+ Button btn2;
+
+ @BindView(R.id.btn_permission_3)
+ Button btn3;
+
+ @BindView(R.id.btn_permission_4)
+ Button btn4;
+
+ @BindView(R.id.btn_permission_5)
+ Button btn5;
+
+ @BindView(R.id.tv_show)
+ TextView tvShow1;
+
+ @BindView(R.id.tv_show1)
+ TextView textView1;
+
+ @BindView(R.id.tv_show2)
+ TextView textView2;
+
+ @BindView(R.id.tv_show3)
+ TextView textView3;
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_permission_test;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initViews();
+ }
+
+ protected void initViews() {
+
+ //只检查权限和结果并显示它
+ btn1.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ boolean b = EasyPermission.build().hasPermission(PermissionTestActivity.this, Manifest.permission.CALL_PHONE);
+ tvShow1.setText(b ? "允许" : "拒绝");
+
+ }
+ });
+
+ //演示只适用于不需要结果
+ btn2.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ EasyPermission.build().requestPermission(PermissionTestActivity.this, Manifest.permission.CALL_PHONE);
+ }
+ });
+
+ //演示只适用于不需要结果
+ btn3.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ NeedReslutPerm();
+ }
+ });
+
+
+ btn4.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ askPerm();
+ }
+ });
+
+ btn5.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ EndlessPerm();
+ }
+ });
+
+ }
+
+
+
+ EasyPermission easyPermission;
+ private void askPerm() {
+ easyPermission = EasyPermission.build()
+ .mRequestCode(RC_CODE_CALLPHONE)
+ .mContext(PermissionTestActivity.this)
+ .mPerms(Manifest.permission.ACCESS_COARSE_LOCATION)
+ .mResult(new EasyPermissionResult() {
+ @Override
+ public void onPermissionsAccess(int requestCode) {
+ super.onPermissionsAccess(requestCode);
+ //做你想做的
+ textView3.setText("do you something here");
+ }
+
+ @Override
+ public void onPermissionsDismiss(int requestCode, @NonNull List permissions) {
+ super.onPermissionsDismiss(requestCode, permissions);
+ //你的权限被用户拒绝了你怎么办
+ textView3.setText("you " + permissions.toString() + " is onPermissionsDismiss");
+ }
+
+ @Override
+ public boolean onDismissAsk(int requestCode, @NonNull List permissions) {
+ //你的权限被用户禁止了并且不能请求了你怎么办
+ textView3.setText("you " + permissions.toString() + " is onDismissAsk");
+ easyPermission.openAppDetails(PermissionTestActivity.this, "Call Phone - Give me the permission to dial the number for you");
+ return true;
+ }
+ });
+ easyPermission.requestPermission();
+ }
+
+ /**
+ * @description 演示需要结果的
+ * @param
+ * @return
+ */
+ private void NeedReslutPerm() {
+ EasyPermission.build()
+ .mRequestCode(RC_CODE_CALLPHONE)
+ .mContext(PermissionTestActivity.this)
+ .mPerms(Manifest.permission.READ_PHONE_STATE)
+ .mResult(new EasyPermissionResult() {
+ @Override
+ public void onPermissionsAccess(int requestCode) {
+ super.onPermissionsAccess(requestCode);
+ //做你想做的
+ textView1.setText("权限已经获取 做你想做的");
+ }
+
+ @Override
+ public void onPermissionsDismiss(int requestCode, @NonNull List permissions) {
+ super.onPermissionsDismiss(requestCode, permissions);
+ //你的权限被用户拒绝了你怎么办
+ textView1.setText("你的权限被用户拒绝了你怎么办 you " + permissions.toString() + " is onPermissionsDismiss");
+ }
+ }).requestPermission();
+ }
+
+ /**
+ * @description 当权限必需时你才能进行下一步你怎么办
+ * @param
+ * @return
+ */
+ private void EndlessPerm() {
+ easyPermission = EasyPermission.build()
+ .mRequestCode(RC_CODE_CALLPHONE)
+ .mContext(PermissionTestActivity.this)
+ .mPerms(Manifest.permission.CALL_PHONE)
+ .mResult(new EasyPermissionResult() {
+ @Override
+ public void onPermissionsAccess(int requestCode) {
+ super.onPermissionsAccess(requestCode);
+ //做你想做的
+ textView3.setText("do you something here");
+ }
+
+ @Override
+ public void onPermissionsDismiss(int requestCode, @NonNull List permissions) {
+ super.onPermissionsDismiss(requestCode, permissions);
+ //你的权限被用户拒绝了你怎么办
+ textView3.setText("you " + permissions.toString() + " is onPermissionsDismiss");
+ //just request it again
+ easyPermission.requestPermission();
+ }
+
+ @Override
+ public boolean onDismissAsk(int requestCode, @NonNull List permissions) {
+ //你的权限被用户禁止了并且不能请求了你怎么办
+ textView3.setText("you " + permissions.toString() + " is 询问");
+ easyPermission.openAppDetails(PermissionTestActivity.this, "Call Phone - Give me the permission to dial the number for you");
+ return true;
+ }
+ });
+ easyPermission.requestPermission();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (EasyPermission.APP_SETTINGS_RC == requestCode) {
+ //设置界面返回
+ //Result from system setting
+ if (easyPermission.hasPermission(PermissionTestActivity.this,Manifest.permission.ACCESS_COARSE_LOCATION)) {
+ //做你想做的
+ textView2.setText("do you something here");
+ } else {
+ //从设置回来还是没给你权限
+ XToast.info(this,"设置里手动 申请 权限 没成功");
+ }
+ }
+ }
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/activity/UtilsActivity.java b/app/src/main/java/com/cain/ui/activity/UtilsActivity.java
new file mode 100644
index 0000000..6bd879d
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/activity/UtilsActivity.java
@@ -0,0 +1,27 @@
+package com.cain.ui.activity;
+
+import android.os.Bundle;
+
+import com.cain.ui.R;
+import com.cain.ui.base.BaseUIActivity;
+import com.cain.ui.fragment.utils.PermissionTestFragment;
+import com.cain.util.sub.app.FragmentUtils;
+
+public class UtilsActivity extends BaseUIActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initViews();
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_utils;
+ }
+
+ private void initViews() {
+ PermissionTestFragment fragment = new PermissionTestFragment();
+ FragmentUtils.add(getSupportFragmentManager(),fragment,R.id.fragment_container_utils);
+ }
+}
diff --git a/app/src/main/java/com/cain/ui/base/BaseHomeFragment.java b/app/src/main/java/com/cain/ui/base/BaseHomeFragment.java
index dfb2380..ab06f1f 100644
--- a/app/src/main/java/com/cain/ui/base/BaseHomeFragment.java
+++ b/app/src/main/java/com/cain/ui/base/BaseHomeFragment.java
@@ -110,7 +110,7 @@ public void onItemClick(View itemView, PageInfo widgetInfo, int pos) {
 }
 
 public MainActivity getContainer() {
- return (MainActivity) getActivity();
+ return null;
 }
 
 @Override
diff --git a/app/src/main/java/com/cain/ui/base/BaseMainFragment.java b/app/src/main/java/com/cain/ui/base/BaseMainFragment.java
new file mode 100644
index 0000000..b2d4f7e
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/base/BaseMainFragment.java
@@ -0,0 +1,87 @@
+package com.cain.ui.base;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.cain.cpage.model.PageInfo;
+import com.cain.cpage.utils.TitleBar;
+import com.cain.cpage.utils.TitleUtils;
+import com.cain.ui.R;
+import com.cain.ui.adapter.WidgetItemAdapter;
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder;
+import com.xuexiang.xui.utils.DensityUtils;
+import com.xuexiang.xui.utils.WidgetUtils;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import butterknife.BindView;
+
+public abstract class BaseMainFragment extends BaseUIFragment implements RecyclerViewHolder.OnItemClickListener {
+
+ @BindView(R.id.recyclerView)
+ RecyclerView mRecyclerView;
+
+ private WidgetItemAdapter mWidgetItemAdapter;
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_home_container;
+ }
+
+ @Override
+ protected void initViews() {
+ initTitle();
+ initRecyclerView();
+ }
+
+ @Override
+ protected void initListeners() {
+
+ }
+
+ private void initRecyclerView() {
+ WidgetUtils.initGridRecyclerView(mRecyclerView, 3, DensityUtils.dp2px(2));
+
+ mWidgetItemAdapter = new WidgetItemAdapter(sortPageInfo(getPageContents()));
+ mWidgetItemAdapter.setOnItemClickListener(this);
+ mRecyclerView.setAdapter(mWidgetItemAdapter);
+ }
+
+ protected TitleBar initTitle() {
+ return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getActivity().finish();
+ }
+ });
+ }
+
+ /**
+ * 进行排序
+ *
+ * @param pageInfoList
+ * @return
+ */
+ private List sortPageInfo(List pageInfoList) {
+ Collections.sort(pageInfoList, new Comparator() {
+ @Override
+ public int compare(PageInfo o1, PageInfo o2) {
+ return o1.getClassPath().compareTo(o2.getClassPath());
+ }
+ });
+ return pageInfoList;
+ }
+
+ /**
+ * @return 页面内容
+ */
+ protected abstract List getPageContents();
+ /**
+ * @return 标题头
+ */
+ protected abstract String getPageTitle();
+}
diff --git a/app/src/main/java/com/cain/ui/base/BaseModuleFragment.java b/app/src/main/java/com/cain/ui/base/BaseModuleFragment.java
new file mode 100644
index 0000000..f464d6a
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/base/BaseModuleFragment.java
@@ -0,0 +1,33 @@
+package com.cain.ui.base;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.cain.cpage.utils.TitleBar;
+import com.cain.cpage.utils.TitleUtils;
+
+/**
+ * 各个模块的 基础类
+ */
+public abstract class BaseModuleFragment extends BaseUIFragment {
+
+
+ @Override
+ protected void initViews() {
+ initTitle();
+ }
+
+ protected TitleBar initTitle() {
+ return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getActivity().finish();
+ }
+ });
+ }
+
+ /**
+ * @return 标题头
+ */
+ protected abstract String getPageTitle();
+}
diff --git a/app/src/main/java/com/cain/ui/base/BaseUIActivity.java b/app/src/main/java/com/cain/ui/base/BaseUIActivity.java
new file mode 100644
index 0000000..ce878df
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/base/BaseUIActivity.java
@@ -0,0 +1,34 @@
+package com.cain.ui.base;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import butterknife.ButterKnife;
+import butterknife.Unbinder;
+
+public abstract class BaseUIActivity extends AppCompatActivity {
+
+ protected Unbinder mUnbinder;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(getLayoutId());
+ mUnbinder = ButterKnife.bind(this);
+ }
+
+
+ protected void onDestroy() {
+ super.onDestroy();
+
+ if (mUnbinder != mUnbinder.EMPTY) {
+ mUnbinder.unbind();
+ }
+ }
+
+ protected abstract int getLayoutId();
+
+}
diff --git a/app/src/main/java/com/cain/ui/base/BaseUIFragment.java b/app/src/main/java/com/cain/ui/base/BaseUIFragment.java
new file mode 100644
index 0000000..7d79fcd
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/base/BaseUIFragment.java
@@ -0,0 +1,69 @@
+package com.cain.ui.base;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import butterknife.ButterKnife;
+import butterknife.Unbinder;
+
+public abstract class BaseUIFragment extends Fragment {
+
+ protected Unbinder mUnbinder;
+ private View mRootView;
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+ mRootView = inflater.inflate(getLayoutId(), container, false);
+ mUnbinder = ButterKnife.bind(this, mRootView);
+ return mRootView;
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ initViews();
+ initListeners();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (mUnbinder != mUnbinder.EMPTY) {
+ mUnbinder.unbind();
+ }
+ }
+
+ /**
+ * 获取根布局
+ *
+ * @return
+ */
+ public View getRootView() {
+ return mRootView;
+ }
+
+ /**
+ * 布局的资源id
+ *
+ * @return
+ */
+ protected abstract int getLayoutId();
+
+ /**
+ * 初始化控件
+ */
+ protected abstract void initViews();
+
+ /**
+ * 初始化监听
+ */
+ protected void initListeners(){};
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/ComponentsFragment.java b/app/src/main/java/com/cain/ui/fragment/ComponentsFragment.java
index b07a98e..ac5b2fb 100644
--- a/app/src/main/java/com/cain/ui/fragment/ComponentsFragment.java
+++ b/app/src/main/java/com/cain/ui/fragment/ComponentsFragment.java
@@ -1,9 +1,15 @@
 package com.cain.ui.fragment;
 
-import com.cain.cpage.AppPageConfig;
+import android.content.Intent;
+import android.view.View;
+import android.widget.Toast;
+
 import com.cain.cpage.model.PageInfo;
-import com.cain.ui.base.BaseHomeFragment;
+import com.cain.ui.activity.ComponentsActivity;
+import com.cain.ui.base.BaseMainFragment;
+import com.xuexiang.xui.widget.toast.XToast;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -12,12 +18,38 @@
 * @CreateDate: 2020年6月3日 2:05 PM
 * @Version: 1.0
 */
-public class ComponentsFragment extends BaseHomeFragment {
+public class ComponentsFragment extends BaseMainFragment {
 
+ private static List pageInfos = new ArrayList();
 
+ static {
+ pageInfos.add(new PageInfo("环形1",""));
+ pageInfos.add(new PageInfo("进度条",""));
+ }
 @Override
 protected List getPageContents() {
- return AppPageConfig.getInstance().getComponents();
+ return pageInfos;
+ }
+
+ @Override
+ protected String getPageTitle() {
+ return "组件";
 }
 
+ @Override
+ public void onItemClick(View itemView, PageInfo widgetInfo, int pos) {
+
+ if (pos == 0){
+ XToast.info(getActivity(),"第1个");
+ Intent intent = new Intent(getActivity(), ComponentsActivity.class);
+ intent.putExtra("item_index",pos);
+ startActivity(intent);
+ }
+
+ if (pos == 1){
+ Toast.makeText(getContext(),"dsd",Toast.LENGTH_SHORT);
+ //XToast.info(getActivity(),"第二个");
+ }
+
+ }
 }
diff --git a/app/src/main/java/com/cain/ui/fragment/ExpandsFragment.java b/app/src/main/java/com/cain/ui/fragment/ExpandsFragment.java
new file mode 100644
index 0000000..0a8a758
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/ExpandsFragment.java
@@ -0,0 +1,51 @@
+package com.cain.ui.fragment;
+
+import android.content.Intent;
+import android.view.View;
+
+import com.cain.cpage.model.PageInfo;
+import com.cain.ui.activity.ExpandsActivity;
+import com.cain.ui.activity.PermissionTestActivity;
+import com.cain.ui.base.BaseMainFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExpandsFragment extends BaseMainFragment {
+
+ private static List pageInfos = new ArrayList();
+
+ static {
+ pageInfos.add(new PageInfo("写法一", ""));
+ pageInfos.add(new PageInfo("设计模式", ""));
+ }
+
+ @Override
+ protected List getPageContents() {
+ return pageInfos;
+ }
+
+ @Override
+ protected String getPageTitle() {
+ return "拓展";
+ }
+
+ @Override
+ public void onItemClick(View itemView, PageInfo item, int position) {
+ switch (position) {
+ case 0:
+ Intent intent = new Intent(getActivity(), PermissionTestActivity.class);
+ startActivity(intent);
+ break;
+ case 1:
+ Intent intent1 = new Intent(getActivity(), ExpandsActivity.class);
+ intent1.putExtra("item_index",position);
+ startActivity(intent1);
+ break;
+ case 2:
+ break;
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/UtilitysFragment.java b/app/src/main/java/com/cain/ui/fragment/UtilitysFragment.java
new file mode 100644
index 0000000..db9b562
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/UtilitysFragment.java
@@ -0,0 +1,58 @@
+package com.cain.ui.fragment;
+
+import android.content.Intent;
+import android.view.View;
+
+import com.cain.cpage.model.PageInfo;
+import com.cain.ui.activity.PermissionTestActivity;
+import com.cain.ui.base.BaseMainFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** 
+ * @Description: 
+ * @Author: cain
+ * @CreateDate: 2020年6月4日 9:16 AM
+ * @Version: 1.0
+ */
+public class UtilitysFragment extends BaseMainFragment {
+
+ private static List pageInfos = new ArrayList();
+
+ static {
+ pageInfos.add(new PageInfo("写法一",""));
+ pageInfos.add(new PageInfo("设计模式",""));
+ }
+
+ @Override
+ protected List getPageContents() {
+ return pageInfos;
+ }
+
+ @Override
+ protected String getPageTitle() {
+ return "工具";
+ }
+
+ @Override
+ public void onItemClick(View itemView, PageInfo widgetInfo, int position) {
+
+ switch (position){
+ case 0:
+ Intent intent = new Intent(getActivity(), PermissionTestActivity.class);
+ startActivity(intent);
+ break;
+ case 1:
+ Intent intent1 = new Intent(getActivity(), PermissionTestActivity.class);
+ startActivity(intent1);
+ break;
+ case 2:
+ break;
+ }
+
+
+ }
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/CameraCircle2Fragment.java b/app/src/main/java/com/cain/ui/fragment/components/circle/CameraCircle2Fragment.java
new file mode 100644
index 0000000..d0425e6
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/CameraCircle2Fragment.java
@@ -0,0 +1,139 @@
+package com.cain.ui.fragment.components.circle;
+
+import android.graphics.PixelFormat;
+import android.hardware.Camera;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.cain.base.base.BaseFragment;
+import com.cain.cpage.annotation.Page;
+import com.cain.cpage.enums.CoreAnim;
+import com.cain.ui.R;
+import com.cain.ui.fragment.components.circle.view.CircleCameraPreview;
+
+import java.io.IOException;
+
+import butterknife.BindView;
+
+@Page(name = "CameraCircle2Fragment", anim = CoreAnim.zoom)
+public class CameraCircle2Fragment extends BaseFragment {
+
+
+ private final String TAG = "PreviewActivity";
+ private Camera camera;
+ private boolean isPreview = false;
+
+ @BindView(R.id.face_view)
+ CircleCameraPreview fv_view;
+
+ @BindView(R.id.ll_root)
+ LinearLayout layout_root;
+
+ @BindView(R.id.btn_start)
+ Button btn_start;
+
+ @BindView(R.id.btn_restore)
+ Button btn_restore;
+
+ @BindView(R.id.tv_countdown)
+ TextView tv_countdown;
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_circle_camera_2;
+ }
+
+ @Override
+ protected void initViews() {
+// addSurfaceView();
+
+
+ btn_start.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ //开始倒计时
+
+ }
+ });
+
+
+ btn_restore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ }
+ });
+
+ }
+
+ private void addSurfaceView() {
+ //添加布局
+ SurfaceView mSurfaceView = new SurfaceView(getActivity());
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+ mSurfaceView.setLayoutParams(params);
+ layout_root.addView(mSurfaceView, 1);
+ //得到getHolder实例
+ SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
+ mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
+ // 添加 Surface 的 callback 接口
+ mSurfaceHolder.addCallback(mSurfaceCallback);
+ }
+
+
+ private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ try {
+ //打开硬件摄像头,这里导包得时候一定要注意是android.hardware.Camera
+ // Camera,open() 默认返回的后置摄像头信息
+ //设置角度,此处 CameraId 我默认 为 1 (前置)
+ if (Camera.getNumberOfCameras()> 1) {
+ camera = Camera.open(1);
+ } else {
+ camera = Camera.open(0);
+ }
+ //设置相机角度
+ camera.setDisplayOrientation(90);
+ //通过SurfaceView显示取景画面
+ camera.setPreviewDisplay(surfaceHolder);
+ //开始预览
+ camera.startPreview();
+ //设置是否预览参数为真
+ isPreview = true;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+ if (camera != null) {
+ if (isPreview) {//正在预览
+ try {
+ camera.stopPreview();
+ camera.release();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ };
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/CameraCircleFragment.java b/app/src/main/java/com/cain/ui/fragment/components/circle/CameraCircleFragment.java
new file mode 100644
index 0000000..829b6d6
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/CameraCircleFragment.java
@@ -0,0 +1,153 @@
+package com.cain.ui.fragment.components.circle;
+
+import android.graphics.PixelFormat;
+import android.hardware.Camera;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.cain.base.base.BaseFragment;
+import com.cain.cpage.annotation.Page;
+import com.cain.cpage.enums.CoreAnim;
+import com.cain.ui.R;
+import com.cain.ui.fragment.components.circle.view.CameraCircleView;
+
+import java.io.IOException;
+
+import butterknife.BindView;
+
+@Page(name = "CameraCircleFragment", anim = CoreAnim.zoom)
+public class CameraCircleFragment extends BaseFragment {
+
+
+ private final String TAG = "PreviewActivity";
+ private Camera camera;
+ private boolean isPreview = false;
+
+ @BindView(R.id.cc_view)
+ CameraCircleView cc_view;
+
+ @BindView(R.id.ll_root)
+ RelativeLayout layout_root;
+
+ @BindView(R.id.btn_start)
+ Button btn_start;
+
+ @BindView(R.id.btn_restore)
+ Button btn_restore;
+
+ @BindView(R.id.tv_countdown)
+ TextView tv_countdown;
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_circle_camera;
+ }
+
+ @Override
+ protected void initViews() {
+ addSurfaceView();
+
+ cc_view.setOnCountDownListener(new CameraCircleView.OnCountDownListener() {
+ @Override
+ public void start() {
+
+ }
+
+ @Override
+ public void finish() {
+
+ }
+ });
+
+
+ btn_start.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ //开始倒计时
+ cc_view.startCountdown();
+
+ }
+ });
+
+
+ btn_restore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ cc_view.stopCountdown();
+ cc_view.reSetRoundProgress();
+ }
+ });
+
+ }
+
+ private void addSurfaceView() {
+ //添加布局
+ SurfaceView mSurfaceView = new SurfaceView(getActivity());
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+ mSurfaceView.setLayoutParams(params);
+ layout_root.addView(mSurfaceView, 1);
+ //得到getHolder实例
+ SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
+ mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
+ // 添加 Surface 的 callback 接口
+ mSurfaceHolder.addCallback(mSurfaceCallback);
+ }
+
+
+ private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ try {
+ //打开硬件摄像头,这里导包得时候一定要注意是android.hardware.Camera
+ // Camera,open() 默认返回的后置摄像头信息
+ //设置角度,此处 CameraId 我默认 为 1 (前置)
+ if (Camera.getNumberOfCameras()> 1) {
+ camera = Camera.open(1);
+ } else {
+ camera = Camera.open(0);
+ }
+ //设置相机角度
+ camera.setDisplayOrientation(90);
+ //通过SurfaceView显示取景画面
+ camera.setPreviewDisplay(surfaceHolder);
+ //开始预览
+ camera.startPreview();
+ //设置是否预览参数为真
+ isPreview = true;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+ if (camera != null) {
+ if (isPreview) {//正在预览
+ try {
+ camera.stopPreview();
+ camera.release();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ };
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/CameraPreviewFragment.java b/app/src/main/java/com/cain/ui/fragment/components/circle/CameraPreviewFragment.java
new file mode 100644
index 0000000..194b32d
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/CameraPreviewFragment.java
@@ -0,0 +1,89 @@
+package com.cain.ui.fragment.components.circle;
+
+import android.hardware.Camera;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.cain.base.base.BaseFragment;
+import com.cain.cpage.annotation.Page;
+import com.cain.cpage.enums.CoreAnim;
+import com.cain.ui.R;
+import com.cain.ui.fragment.components.circle.preview.CameraPreview;
+import com.cain.ui.fragment.components.circle.preview.CircleCameraLayout;
+
+import butterknife.BindView;
+
+@Page(name = "CameraPreviewFragment", anim = CoreAnim.zoom)
+public class CameraPreviewFragment extends BaseFragment {
+
+
+ private final String TAG = "PreviewActivity";
+ private Camera camera;
+ private boolean isPreview = false;
+
+ private CameraPreview cameraPreview;
+
+ @BindView(R.id.rootLayout)
+ CircleCameraLayout rootLayout;
+
+ @BindView(R.id.ll_root)
+ LinearLayout layout_root;
+
+ @BindView(R.id.btn_start)
+ Button btn_start;
+
+ @BindView(R.id.btn_restore)
+ Button btn_restore;
+
+ @BindView(R.id.tv_countdown)
+ TextView tv_countdown;
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_circle_camera_pre;
+ }
+
+ @Override
+ protected void initViews() {
+
+
+ startCamera();
+
+
+ btn_start.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ //开始倒计时
+
+
+ }
+ });
+
+
+ btn_restore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ }
+ });
+
+ }
+
+
+ private void startCamera() {
+ if (null != cameraPreview) cameraPreview.releaseCamera();
+ cameraPreview = new CameraPreview(getActivity());
+ rootLayout.removeAllViews();
+ rootLayout.setCameraPreview(cameraPreview);
+ rootLayout.startView();
+
+ }
+
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/CircleIndexFragment.java b/app/src/main/java/com/cain/ui/fragment/components/circle/CircleIndexFragment.java
new file mode 100644
index 0000000..7ce7b51
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/CircleIndexFragment.java
@@ -0,0 +1,98 @@
+package com.cain.ui.fragment.components.circle;
+
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.cain.base.base.BaseFragment;
+import com.cain.cpage.annotation.Page;
+import com.cain.cpage.enums.CoreAnim;
+import com.cain.ui.R;
+import com.cain.util.sub.app.FragmentUtils;
+
+import butterknife.BindView;
+
+@Page(name = "CircleIndexFragment", anim = CoreAnim.zoom)
+public class CircleIndexFragment extends BaseFragment {
+
+ @BindView(R.id.btn_1)
+ Button btn1;
+
+ @BindView(R.id.btn_2)
+ Button btn2;
+
+ @BindView(R.id.btn_3)
+ Button btn3;
+
+ @BindView(R.id.btn_4)
+ Button btn4;
+
+ @BindView(R.id.btn_5)
+ Button btn5;
+
+ @BindView(R.id.tv_show)
+ TextView tvShow1;
+
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_circle_index;
+ }
+
+ @Override
+ protected void initViews() {
+
+ //只检查权限和结果并显示它
+ btn1.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ CountDownFragment fragment = new CountDownFragment();
+ FragmentUtils.add(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components);
+ }
+ });
+
+ //演示只适用于不需要结果
+ btn2.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ CountProgressFragment countProgressFragment = new CountProgressFragment();
+ FragmentUtils.replace(getActivity().getSupportFragmentManager(),countProgressFragment,R.id.fragment_container_components);
+ }
+ });
+
+ btn3.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ CameraCircleFragment fragment = new CameraCircleFragment();
+ FragmentUtils.replace(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components);
+
+ }
+ });
+
+ btn4.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ CameraCircle2Fragment fragment = new CameraCircle2Fragment();
+ FragmentUtils.replace(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components);
+
+ }
+ });
+
+ btn5.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ CameraPreviewFragment fragment = new CameraPreviewFragment();
+ FragmentUtils.replace(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components);
+
+ }
+ });
+
+ }
+
+
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/CountDownFragment.java b/app/src/main/java/com/cain/ui/fragment/components/circle/CountDownFragment.java
new file mode 100644
index 0000000..a0b23bd
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/CountDownFragment.java
@@ -0,0 +1,81 @@
+package com.cain.ui.fragment.components.circle;
+
+import android.view.View;
+import android.widget.Button;
+
+import com.cain.base.base.BaseFragment;
+import com.cain.cpage.annotation.Page;
+import com.cain.cpage.enums.CoreAnim;
+import com.cain.ui.R;
+import com.cain.ui.fragment.components.circle.view.CountDownView;
+import com.xuexiang.xui.widget.toast.XToast;
+
+import butterknife.BindView;
+
+@Page(name = "CountDownFragment", anim = CoreAnim.zoom)
+public class CountDownFragment extends BaseFragment {
+
+ @BindView(R.id.cd_view)
+ CountDownView countDownView;
+
+ @BindView(R.id.btn_start)
+ Button btn1;
+
+ @BindView(R.id.btn_restore)
+ Button btn2;
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_circle_count_down;
+ }
+
+ @Override
+ protected void initViews() {
+
+ countDownView.setOnCountDownListener(new CountDownView.OnCountDownListener() {
+ @Override
+ public void start() {
+ XToast.info(getActivity(),"start");
+ }
+
+ @Override
+ public void finish() {
+ XToast.info(getActivity(),"finish");
+ }
+ });
+
+
+
+ //停止倒计时
+ /*countDownView.stopCountdown();
+
+ countDownView.invalidate();*/
+
+ btn1.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ //开始倒计时
+ countDownView.startCountdown();
+ }
+ });
+
+ btn2.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ countDownView.stopCountdown();
+
+ countDownView.reSetRoundProgress();
+ }
+ });
+
+
+
+
+ }
+
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/CountProgressFragment.java b/app/src/main/java/com/cain/ui/fragment/components/circle/CountProgressFragment.java
new file mode 100644
index 0000000..0278908
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/CountProgressFragment.java
@@ -0,0 +1,88 @@
+package com.cain.ui.fragment.components.circle;
+
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.cain.base.base.BaseFragment;
+import com.cain.cpage.annotation.Page;
+import com.cain.cpage.enums.CoreAnim;
+import com.cain.ui.R;
+import com.cain.ui.fragment.components.circle.view.CircleProgressbar;
+
+import butterknife.BindView;
+
+@Page(name = "CountProgressFragment", anim = CoreAnim.zoom)
+public class CountProgressFragment extends BaseFragment {
+
+ @BindView(R.id.cp_progress_first_1)
+ CircleProgressbar circleProgressbarFirst;
+ @BindView(R.id.cp_progress_second)
+ CircleProgressbar circleProgressbarSecond;
+ @BindView(R.id.cp_progress_third)
+ CircleProgressbar circleProgressbarThird;
+
+ @BindView(R.id.btn_start)
+ Button btn_start;
+
+ @BindView(R.id.btn_restore)
+ Button btn_restore;
+
+ @BindView(R.id.tv_countdown)
+ TextView tv_countdown;
+
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_circle_progress;
+ }
+
+ @Override
+ protected void initViews() {
+ circleProgressbarSecond.setOnProgressbarChangeListener(new CircleProgressbar.OnProgressbarChangeListener() {
+ @Override
+ public void onProgressChanged(CircleProgressbar circleSeekbar, float progress, boolean fromUser) {
+ //UILog.e("progress->"+progress+"fromUser->"+fromUser);
+ Log.e("onProgressChanged->","progress->"+progress+"fromUser->"+fromUser);
+ }
+
+ @Override
+ public void onStartTracking(CircleProgressbar circleSeekbar) {
+
+ }
+
+ @Override
+ public void onStopTracking(CircleProgressbar circleSeekbar) {
+
+ }
+ });
+
+ btn_start.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+// circleProgressbarFirst.setProgressWithAnimation(0, 8000);
+ circleProgressbarSecond.setProgressWithAnimation(0, 8000);
+// circleProgressbarThird.setProgressWithAnimation(0, 6000);
+ }
+ });
+
+
+ btn_restore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ //circleProgressbarFirst.setProgress(0);
+ circleProgressbarSecond.setProgress(100);
+ //circleProgressbarThird.setProgress(0);
+ //tv_countdown.setText((int) circleProgressbarThird.getMaxProgress() + "");
+ }
+ });
+
+ }
+
+
+
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CameraListener.java b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CameraListener.java
new file mode 100644
index 0000000..93d3f7e
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CameraListener.java
@@ -0,0 +1,13 @@
+package com.cain.ui.fragment.components.circle.preview;
+
+import android.graphics.Bitmap;
+
+/**
+ * Created by dong on 2018年5月23日.
+ */
+
+public interface CameraListener {
+
+ void onCaptured(Bitmap bitmap);
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CameraPreview.java b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CameraPreview.java
new file mode 100644
index 0000000..8190b1b
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CameraPreview.java
@@ -0,0 +1,222 @@
+package com.cain.ui.fragment.components.circle.preview;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.hardware.Camera;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import java.io.IOException;
+
+/**
+ * Created by dong on 2018年5月23日.
+ */
+
+public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
+ private static final String TAG = "CameraPreview";
+
+ private Camera mCamera;
+ private SurfaceHolder mHolder;
+ private Activity mContext;
+ private CameraListener listener;
+ private int cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
+ private int displayDegree = 90;
+
+ public CameraPreview(Activity context) {
+ super(context);
+ mContext = context;
+ mCamera = Camera.open(cameraId);
+ mHolder = getHolder();
+ mHolder.addCallback(this);
+ mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ }
+
+ public void setCameraListener(CameraListener listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * 拍照获取bitmap
+ */
+ public void captureImage() {
+ try {
+ mCamera.takePicture(null, null, new Camera.PictureCallback() {
+ @Override
+ public void onPictureTaken(byte[] data, Camera camera) {
+ if (null != listener) {
+ Bitmap bitmap = rotateBitmap(BitmapFactory.decodeByteArray(data, 0, data.length),
+ displayDegree);
+ listener.onCaptured(bitmap);
+ }
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ if (null != listener) {
+ listener.onCaptured(null);
+ }
+ }
+ }
+
+ /**
+ * 预览拍照
+ */
+ public void startPreview() {
+ mCamera.startPreview();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (null != mCamera) {
+ mCamera.autoFocus(null);
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ try {
+ startCamera(holder);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ if (mHolder.getSurface() == null) {
+ return;
+ }
+ try {
+ mCamera.stopPreview();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ startCamera(mHolder);
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ private void startCamera(SurfaceHolder holder) throws IOException {
+ mCamera.setPreviewDisplay(holder);
+ setCameraDisplayOrientation(mContext, cameraId, mCamera);
+
+ Camera.Size preSize = getCameraSize();
+
+ Camera.Parameters parameters = mCamera.getParameters();
+ parameters.setPreviewSize(preSize.width, preSize.height);
+ parameters.setPictureSize(preSize.width, preSize.height);
+ parameters.setJpegQuality(100);
+ mCamera.setParameters(parameters);
+ mCamera.startPreview();
+ }
+
+ public Camera.Size getCameraSize() {
+ if (null != mCamera) {
+ Camera.Parameters parameters = mCamera.getParameters();
+ DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+ Camera.Size preSize = Util.getCloselyPreSize(true, metrics.widthPixels, metrics.heightPixels,
+ parameters.getSupportedPreviewSizes());
+ return preSize;
+ }
+ return null;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ releaseCamera();
+ }
+
+
+ /**
+ * Android API: Display Orientation Setting
+ * Just change screen display orientation,
+ * the rawFrame data never be changed.
+ */
+ private void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ Camera.getCameraInfo(cameraId, info);
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+ int degrees = 0;
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ }
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ displayDegree = (info.orientation + degrees) % 360;
+ displayDegree = (360 - displayDegree) % 360; // compensate the mirror
+ } else {
+ displayDegree = (info.orientation - degrees + 360) % 360;
+ }
+ camera.setDisplayOrientation(displayDegree);
+ }
+
+
+ /**
+ * 将图片按照某个角度进行旋转
+ *
+ * @param bm 需要旋转的图片
+ * @param degree 旋转角度
+ * @return 旋转后的图片
+ */
+ private Bitmap rotateBitmap(Bitmap bm, int degree) {
+ Bitmap returnBm = null;
+
+ // 根据旋转角度,生成旋转矩阵
+ Matrix matrix = new Matrix();
+ matrix.postRotate(degree);
+ try {
+ // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
+ returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
+ bm.getHeight(), matrix, true);
+ } catch (OutOfMemoryError e) {
+ e.printStackTrace();
+ }
+ if (returnBm == null) {
+ returnBm = bm;
+ }
+ if (bm != returnBm) {
+ bm.recycle();
+ }
+ return returnBm;
+ }
+
+ /**
+ * 释放资源
+ */
+ public synchronized void releaseCamera() {
+ try {
+ if (null != mCamera) {
+ mCamera.setPreviewCallback(null);
+ mCamera.stopPreview();//停止预览
+ mCamera.release(); // 释放相机资源
+ mCamera = null;
+ }
+ if (null != mHolder) {
+ mHolder.removeCallback(this);
+ mHolder = null;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CircleCameraLayout.java b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CircleCameraLayout.java
new file mode 100644
index 0000000..93c950b
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CircleCameraLayout.java
@@ -0,0 +1,173 @@
+package com.cain.ui.fragment.components.circle.preview;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.RequiresApi;
+
+import com.cain.ui.R;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Created by dong on 2018年5月23日.
+ */
+
+public class CircleCameraLayout extends RelativeLayout {
+
+ public CircleCameraLayout(Context context) {
+ super(context);
+ init(context, null, -1, -1);
+ }
+
+ public CircleCameraLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs, -1, -1);
+ }
+
+ public CircleCameraLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs, defStyleAttr, -1);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ public CircleCameraLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+
+ private Timer timer;
+ private TimerTask pressTask;
+ private Context mContext;
+ private int circleWidth = 0;//指定半径
+ private int borderWidth = 0;//指定边框
+ private CameraPreview cameraPreview;//摄像预览
+
+ private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ mContext = context;
+ timer = new Timer();
+ if (attrs != null && defStyleAttr == -1 && defStyleRes == -1) {
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleCameraLayout, defStyleAttr, defStyleRes);
+ circleWidth = (int) typedArray.getDimension(R.styleable.CircleCameraLayout_circle_camera_width, ViewGroup.LayoutParams.WRAP_CONTENT);
+ borderWidth = (int) typedArray.getDimension(R.styleable.CircleCameraLayout_border_width, 5);
+ typedArray.recycle();
+ }
+ startView();
+ }
+
+ /**
+ * 设置照相预览
+ *
+ * @param cameraPreview
+ */
+ public void setCameraPreview(CameraPreview cameraPreview) {
+ this.cameraPreview = cameraPreview;
+ }
+
+ /**
+ * 释放回收
+ */
+ public void release() {
+ if (null != pressTask) {
+ pressTask.cancel();
+ pressTask = null;
+ }
+ if (null != timer) {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+ //延时启动摄像头
+ public void startView() {
+ pressTask = new TimerTask() {
+ @Override
+ public void run() {
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ pressTask.cancel();
+ pressTask = null;
+ if (null != cameraPreview) {
+ show();
+ } else {
+ startView();
+ }
+ }
+ });
+ }
+ };
+ timer.schedule(pressTask, 50);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void show() {
+ //cmaera根view--layout
+ RelativeLayout cameraRoot = new RelativeLayout(mContext);
+ LayoutParams rootParams = new LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ rootParams.addRule(CENTER_IN_PARENT, TRUE);
+ cameraRoot.setBackgroundColor(Color.TRANSPARENT);
+ cameraRoot.setClipChildren(false);
+
+
+ //camera--layout
+ FrameLayout cameraLayout = new FrameLayout(mContext);
+ Camera.Size preSize = cameraPreview.getCameraSize();
+ int cameraHeight = (int) ((float) preSize.width / (float) preSize.height * circleWidth);
+ LayoutParams cameraParams = new LayoutParams(circleWidth, cameraHeight);
+ cameraParams.addRule(CENTER_IN_PARENT, TRUE);
+ cameraLayout.setLayoutParams(cameraParams);
+ cameraLayout.addView(cameraPreview);
+
+ cameraLayout.setOutlineProvider(viewOutlineProvider);//把自定义的轮廓提供者设置给imageView
+ cameraLayout.setClipToOutline(true);//开启裁剪
+
+ //circleView--layout
+// CircleView circleView = new CircleView(mContext);
+ CircleView2 circleView = new CircleView2(mContext);
+ circleView.setBorderWidth(circleWidth, borderWidth);
+
+ //设置margin值---隐藏超出部分布局
+ int margin = (cameraHeight - circleWidth) / 2 - borderWidth / 2;
+ rootParams.setMargins(0, -margin, 0, -margin);
+ cameraRoot.setLayoutParams(rootParams);
+
+ //添加camera
+ cameraRoot.addView(cameraLayout);
+ //添加circle
+ cameraRoot.addView(circleView);
+ //添加根布局
+ this.addView(cameraRoot);
+ }
+
+ //自定义一个轮廓提供者
+ public ViewOutlineProvider viewOutlineProvider = new ViewOutlineProvider() {
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void getOutline(View view, Outline outline) {
+ //裁剪成一个圆形
+ int left0 = 0;
+ int top0 = (view.getHeight() - view.getWidth()) / 2;
+ int right0 = view.getWidth();
+ int bottom0 = (view.getHeight() - view.getWidth()) / 2 + view.getWidth();
+ outline.setOval(left0, top0, right0, bottom0);
+ }
+ };
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CircleView2.java b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CircleView2.java
new file mode 100644
index 0000000..31f99d4
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/CircleView2.java
@@ -0,0 +1,80 @@
+package com.cain.ui.fragment.components.circle.preview;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.Nullable;
+
+import com.cain.ui.R;
+
+
+/**
+ * Created by dong on 2018年5月23日.
+ * kl
+ */
+
+public class CircleView2 extends View {
+
+ public CircleView2(Context context) {
+ super(context);
+ init();
+ }
+
+ public CircleView2(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CircleView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private Paint paint;
+ private int borderWidth;
+ private RectF rectF;
+
+ /**
+ * @param circleWidth 指定view宽高
+ * @param borderWidth 边框宽度
+ */
+ public void setBorderWidth(int circleWidth, int borderWidth) {
+ this.borderWidth = borderWidth;
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(circleWidth, circleWidth + borderWidth * 2);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+ setLayoutParams(params);
+ }
+
+ private void init() {
+ setBackgroundColor(Color.TRANSPARENT);
+ //圆形边框
+ int borderColor = getResources().getColor(R.color.colorAccent);
+ paint = new Paint();
+ paint.setColor(borderColor);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setAntiAlias(true);//抗锯齿
+ paint.setDither(true);//防抖动
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (borderWidth != 0) {
+ paint.setStrokeWidth(borderWidth);
+ int left = borderWidth / 2;
+ int top = (getHeight() - (getWidth())) / 2 + borderWidth / 2;
+ int right = getWidth() - borderWidth / 2;
+ int bottom = (getHeight() - getWidth()) / 2 + getWidth() - borderWidth / 2;
+
+ if (null == rectF) rectF = new RectF(left, top, right, bottom);
+ canvas.drawArc(rectF, 0, 360, false, paint);
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/preview/Util.java b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/Util.java
new file mode 100644
index 0000000..0e31de4
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/preview/Util.java
@@ -0,0 +1,72 @@
+package com.cain.ui.fragment.components.circle.preview;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.Camera;
+
+import androidx.core.content.ContextCompat;
+
+import java.util.List;
+
+/**
+ * Created by dong on 2018年5月23日.
+ */
+
+public class Util {
+
+ /**
+ * 通过对比得到与宽高比最接近的预览尺寸(如果有相同尺寸,优先选择)
+ *
+ * @param isPortrait 是否竖屏
+ * @param surfaceWidth 需要被进行对比的原宽
+ * @param surfaceHeight 需要被进行对比的原高
+ * @param preSizeList 需要对比的预览尺寸列表
+ * @return 得到与原宽高比例最接近的尺寸
+ */
+ public static Camera.Size getCloselyPreSize(boolean isPortrait, int surfaceWidth, int surfaceHeight, List preSizeList) {
+ int reqTmpWidth;
+ int reqTmpHeight;
+ // 当屏幕为垂直的时候需要把宽高值进行调换,保证宽大于高
+ if (isPortrait) {
+ reqTmpWidth = surfaceHeight;
+ reqTmpHeight = surfaceWidth;
+ } else {
+ reqTmpWidth = surfaceWidth;
+ reqTmpHeight = surfaceHeight;
+ }
+ //先查找preview中是否存在与surfaceview相同宽高的尺寸
+ for (Camera.Size size : preSizeList) {
+ if ((size.width == reqTmpWidth) && (size.height == reqTmpHeight)) {
+ return size;
+ }
+ }
+ // 得到与传入的宽高比最接近的size
+ float reqRatio = ((float) reqTmpWidth) / reqTmpHeight;
+ float curRatio, deltaRatio;
+ float deltaRatioMin = Float.MAX_VALUE;
+ Camera.Size retSize = null;
+ for (Camera.Size size : preSizeList) {
+ curRatio = ((float) size.width) / size.height;
+ deltaRatio = Math.abs(reqRatio - curRatio);
+ if (deltaRatio < deltaRatioMin) { + deltaRatioMin = deltaRatio; + retSize = size; + } + } + return retSize; + } + + + /** + * 检查是否拥有指定的所有权限 + */ + public static boolean checkPermissionAllGranted(Context context, String[] permissions) { + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { + // 只要有一个权限没有被授予, 则直接返回 false + return false; + } + } + return true; + } +} diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/view/CameraCircleView.java b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CameraCircleView.java new file mode 100644 index 0000000..f95a193 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CameraCircleView.java @@ -0,0 +1,272 @@ +package com.cain.ui.fragment.components.circle.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Handler; +import android.os.Message; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; + +import com.cain.ui.R; + + +/** + * 倒计时view 圆形广告倒计时 + * Created by dalong on 2016/11/14. + */ + +public class CameraCircleView extends View implements View.OnClickListener { + + //默认文字 + private final String mDefult; + //背景颜色 + private int mBackgroundColor; + //圆环颜色 + private int mRoundColor; + //进度颜色 + private int mRoundProgressColor; + //圆环的宽度 + private float mRoundWidth; + //文字 + private String mText; + //文字的大小 + private float mTextSize; + //文字的颜色 + private int mTextColor; + //倒计时的时间 + private int mCountdownTime; + //背景圆画笔 + private Paint mBackgroundPaint; + // 圆环和进度画笔 + private Paint mBorderPaint; + //文字画笔 + private TextPaint mTextPaint; + //文字换行的一个工具类 实现了文本绘制换行处理 + private StaticLayout mStaticLayout; + //中间坐标 + private int centerX,centerY; + //进度值 + private int mRoundProgress; + //一秒添加的度数 + private int mProgressPart; + + + public CameraCircleView(Context context) { + this(context,null); + } + + public CameraCircleView(Context context, AttributeSet attrs) { + this(context, attrs,0); + } + + public CameraCircleView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CountDownView); + mBackgroundColor=typedArray.getColor(R.styleable.CountDownView_backgroundColor, Color.GRAY); + mRoundColor=typedArray.getColor(R.styleable.CountDownView_roundColor,Color.RED); + mRoundProgressColor=typedArray.getColor(R.styleable.CountDownView_roundProgressColor,Color.YELLOW); + mRound + m + mTextSize = typedArray.getDimensionPixelSize(R.styleable.CountDownView_textSize, (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); + mTextColor=typedArray.getColor(R.styleable.CountDownView_textColor,Color.RED); + mCountdownTime=typedArray.getInt(R.styleable.CountDownView_countdownTime,3000); + typedArray.recycle(); + + init(); + } + + private void init() { + if(TextUtils.isEmpty(mText))m + setOnClickListener(this); + //求出每秒需要前进的度数 + mProgressPart=360/(mCountdownTime/1000); + mBackgroundPaint = new Paint(); + mBackgroundPaint.setAntiAlias(true); + mBackgroundPaint.setDither(true); + mBackgroundPaint.setColor(mBackgroundColor); + mBackgroundPaint.setStyle(Paint.Style.FILL); + + mBorderPaint = new Paint(); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setDither(true); + mBorderPaint.setStrokeWidth(mRoundWidth); + mBorderPaint.setStyle(Paint.Style.STROKE); + + + + mTextPaint = new TextPaint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setDither(true); + mTextPaint.setColor(mTextColor); + mTextPaint.setTextSize(mTextSize); + mTextPaint.setTextAlign(Paint.Align.CENTER); + + + int textWidth = (int) mTextPaint.measureText(mText.substring(0, (mText.length() + 1) / 2)); + mStaticLayout = new StaticLayout(mText, mTextPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 1F, 0, false); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int widthMode=MeasureSpec.getMode(widthMeasureSpec); + int widthSize=MeasureSpec.getSize(widthMeasureSpec); + int heightMode=MeasureSpec.getMode(heightMeasureSpec); + int heightSize=MeasureSpec.getSize(heightMeasureSpec); + + //如果没有设置宽度就使用文字的宽度来设置 + if (widthMode != MeasureSpec.EXACTLY) { + widthSize = mStaticLayout.getWidth()+getPaddingRight()+getPaddingLeft(); + } + //如果没有设置高度就使用文字的高度来设置 + if (heightMode != MeasureSpec.EXACTLY) { + heightSize = mStaticLayout.getHeight()+getPaddingBottom()+getPaddingTop(); + } + int max=Math.max(widthSize,heightSize); + setMeasuredDimension(max, max); + } + + + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + centerX=getMeasuredWidth()/2; + centerY=getMeasuredHeight()/2; + drawBackground(canvas); + drawRound(canvas); + drawRoundProgress(canvas); + drawText(canvas); + } + + /** + * 绘制背景圆 + * @param canvas + */ + private void drawBackground(Canvas canvas) { + canvas.drawCircle(centerX,centerY,Math.max(centerX,centerY),mBackgroundPaint); + } + + + /** + * 绘制圆环 + * @param canvas + */ + private void drawRound(Canvas canvas) { + mBorderPaint.setColor(mRoundColor); + int min=Math.max(centerX,centerY); + canvas.drawCircle(centerX,centerY,min-mRoundWidth/2,mBorderPaint); + } + + + /** + * 绘制进度条 + * @param canvas + */ + private void drawRoundProgress(Canvas canvas) { + mBorderPaint.setColor(mRoundProgressColor); + int min=Math.min(centerX,centerY); + int radius = (int) (min - mRoundWidth / 2); + RectF rectF = new RectF(centerX -radius,centerY -radius, centerX + radius, centerY + radius); + canvas.drawArc(rectF, 0, mRoundProgress, false, mBorderPaint); + } + + + /** + * 绘制文字 + * @param canvas + */ + private void drawText(Canvas canvas) { + canvas.translate(centerX,centerY- mStaticLayout.getHeight() / 2); + mStaticLayout.draw(canvas); + } + + /** + * 开始倒计时 + */ + public void startCountdown() { + if(mRoundProgress>=360)mRoundProgress=0;
+ if(mOnCountDownListener!=null)mOnCountDownListener.start();
+ if(mHandler!=null)mHandler.sendEmptyMessageDelayed(mMsgWhat,1000);
+ }
+
+ /**
+ * 停止倒计时
+ */
+ public void reSetRoundProgress() {
+ mRoundProgress=0;
+ invalidate();
+ }
+
+ /**
+ * 停止倒计时
+ */
+ public void stopCountdown() {
+ if(mHandler!=null)mHandler.removeMessages(mMsgWhat);
+ }
+
+ /**
+ * 更新进度条
+ */
+ public final int mMsgWhat=1000;
+ Handler mHandler=new Handler(){
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what){
+ case mMsgWhat:
+ mRoundProgress+=mProgressPart;
+ if(mRoundProgress>=360){
+ mHandler.removeMessages(mMsgWhat);
+ if(mOnCountDownListener!=null)mOnCountDownListener.finish();
+ }else{
+ mHandler.sendEmptyMessageDelayed(mMsgWhat,1000);
+ }
+ postInvalidate();
+ break;
+ }
+ }
+ };
+
+ OnCountDownListener mOnCountDownListener;
+
+ /**
+ * 接口实现
+ * @param l
+ */
+ public void setOnCountDownListener(OnCountDownListener l) {
+ this.mOnCountDownListener=l;
+ }
+
+ /**
+ * 点击直接结束
+ * @param v
+ */
+ @Override
+ public void onClick(View v) {
+ if(mHandler!=null) mHandler.removeMessages(mMsgWhat);
+ if(mOnCountDownListener!=null)mOnCountDownListener.finish();
+ }
+
+ /**
+ * 倒计时回调接口
+ */
+ public interface OnCountDownListener{
+ void start();
+ void finish();
+ }
+
+
+}
diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/view/CircleCameraPreview.java b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CircleCameraPreview.java
new file mode 100644
index 0000000..11211a9
--- /dev/null
+++ b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CircleCameraPreview.java
@@ -0,0 +1,373 @@
+package com.cain.ui.fragment.components.circle.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ImageFormat;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Region;
+import android.hardware.Camera;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 圆形摄像头预览控件
+ *
+ * 支持暂停预览,圆形的摄像头预览
+ */
+public class CircleCameraPreview extends SurfaceView implements SurfaceHolder.Callback {
+
+ private static final String TAG = "CircleCameraPreview";
+
+ /**
+ * 相机ID
+ */
+ private static final int CAMERA_ID = Camera.CameraInfo.CAMERA_FACING_FRONT;
+
+ /**
+ * 相机对象
+ */
+ private Camera mCamera;
+
+ /**
+ * 半径
+ */
+ private int radius;
+
+ /**
+ * 中心点坐标
+ */
+ private Point centerPoint;
+
+ /**
+ * 剪切路径
+ */
+ private Path clipPath;
+
+ /**
+ * 是否在预览
+ */
+ private boolean isPreviewing;
+
+ /**
+ * 是否已经设置过窗口尺寸
+ */
+ private boolean isSizeFitted = false;
+
+ /**
+ * 预览回调
+ */
+ private Camera.PreviewCallback previewCallback;
+
+
+ public CircleCameraPreview(Context context) {
+ super(context);
+ init();
+ }
+
+ public CircleCameraPreview(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CircleCameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ /**
+ * 初始化
+ */
+ private void init() {
+ this.setFocusable(true);
+ this.setFocusableInTouchMode(true);
+ getHolder().addCallback(this);
+ clipPath = new Path();
+ centerPoint = new Point();
+ }
+
+
+ /**
+ * 暂停预览功能
+ *
+ * @return true - 开启预览; false - 暂停预览
+ */
+ public boolean pause() {
+ Log.i(TAG, "pause: " + isPreviewing);
+ if (isPreviewing) {
+ isPreviewing = false;
+ mCamera.stopPreview();
+ } else {
+ isPreviewing = true;
+ mCamera.startPreview();
+ }
+ return isPreviewing;
+ }
+
+ /**
+ * 暂停预览功能
+ *
+ * @param state true - 开启预览; false - 暂停预览
+ */
+ public void pause(boolean state) {
+ if (!state) {
+ isPreviewing = false;
+ mCamera.stopPreview();
+ } else {
+ isPreviewing = true;
+ mCamera.startPreview();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ // 坐标转换为实际像素
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ // 计算出圆形的中心点
+ centerPoint.x = widthSize>> 1;
+ centerPoint.y = heightSize>> 1;
+ // 计算出最短的边的一半作为半径
+ radius = ( centerPoint.x> centerPoint.y) ? centerPoint.y : centerPoint.x;
+ Log.i(TAG, "onMeasure: " + centerPoint.toString());
+ clipPath.reset();
+ clipPath.addCircle(centerPoint.x, centerPoint.y, radius, Path.Direction.CCW);
+ setMeasuredDimension(widthSize, heightSize);
+ }
+
+
+ /**
+ * 绘制
+ *
+ * @param canvas 画布
+ */
+ @Override
+ public void draw(Canvas canvas) {
+ //裁剪画布,并设置其填充方式
+ if (Build.VERSION.SDK_INT>= 26) {
+ canvas.clipPath(clipPath);
+ } else {
+ canvas.clipPath(clipPath, Region.Op.REPLACE);
+ }
+ super.draw(canvas);
+ }
+
+ /**
+ * 打开相机
+ *
+ * @param holder
+ */
+ private void openCamera(SurfaceHolder holder) {
+ // 打开相机
+ mCamera = Camera.open(CAMERA_ID);
+ try {
+ mCamera.setPreviewDisplay(holder);
+ } catch (IOException e) {
+ Log.e(TAG, "相机开始失败", e);
+ closeCamera();
+ return;
+ }
+
+ Camera.Parameters params = mCamera.getParameters();
+
+ /*
+ * 设置自动对焦
+ */
+ List supportedFocusModes = params.getSupportedFocusModes();
+ if (supportedFocusModes != null && supportedFocusModes.size()> 0) {
+ if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
+ params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
+ } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
+ params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
+ } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
+ params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
+ }
+ }
+
+ // 获取支持的最大的 4:3 比例尺寸图片尺寸
+ Camera.Size maxSize = getMaxPictureSize(params);
+
+ // 设置预览尺寸为图像尺寸
+ params.setPreviewSize(maxSize.width, maxSize.height);
+ // 设置预览编码图像编码格式为 NV21
+ params.setPreviewFormat(ImageFormat.NV21);
+ mCamera.setParameters(params);
+ // 获取相机应旋转角度
+ int rotate = getRotateAngle();
+ // 根据旋转角度调整view的宽高
+ changeViewSize(rotate);
+ mCamera.setDisplayOrientation(rotate);
+
+ if (previewCallback != null) {
+ // 设置预览回调
+ mCamera.setPreviewCallback(previewCallback);
+ }
+
+ // 开始相机预览
+ mCamera.startPreview();
+
+ isPreviewing = true;
+ }
+
+ /**
+ * 根据相机旋转动态修改view的尺寸
+ * 

+ * 以抵消失真的现象 + * + * @param rotate 旋转角度 + */ + private void changeViewSize(int rotate) { + if (isSizeFitted) { + // 如果屏幕尺寸已经重设过那么,则认为不需要再设置 + return; + } + isSizeFitted = true; + + DisplayMetrics metrics = new DisplayMetrics(); + ((WindowManager) getContext() + .getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getMetrics(metrics); + + ViewGroup.LayoutParams layoutParams = this.getLayoutParams(); + if (rotate == 0) { + layoutParams.height = layoutParams.width * 3 / 4; + } else { + layoutParams.width = layoutParams.width * 3 / 4; + } + this.setLayoutParams(layoutParams); + } + + + private int getRotateAngle() { + Camera.CameraInfo info = new Camera.CameraInfo(); + Camera.getCameraInfo(CAMERA_ID, info); + // 获取当前手机的选装角度 + int rotation = ((WindowManager) getContext() + .getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getRotation(); + int degrees = 0; + switch (rotation) { + case Surface.ROTATION_0: + degrees = 0; + break; + case Surface.ROTATION_90: + degrees = 90; + break; + case Surface.ROTATION_180: + degrees = 180; + break; + case Surface.ROTATION_270: + degrees = 270; + break; + } + + int result; + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + result = (info.orientation + degrees) % 360; + result = (360 - result) % 360; + } else { + result = (info.orientation - degrees + 360) % 360; + } + return result; + } + + + + /** + * 相机预览回调 + * + * @param cb 回调 + * @return this + */ + public CircleCameraPreview setOnPreview(Camera.PreviewCallback cb) { + previewCallback = cb; + if (mCamera != null) { + mCamera.setPreviewCallback(cb); + } + return this; + } + + + /** + * 获取最大支持 4:3 图像尺寸 + * + * @param params 参数 + * @return 最大尺寸 + */ + private Camera.Size getMaxPictureSize(Camera.Parameters params) { + List previewSizes = params.getSupportedPictureSizes(); + int maxArea = -1; + Camera.Size maxSize = null; + + for (Camera.Size size : previewSizes) { + Log.i(TAG, "Support size -> " + size.width + " x " + size.height); + + int gcd = gcd(size.width, size.height); + int w = size.width / gcd; + int h = size.height / gcd; + if (w == 4 && h == 3 && (size.width * size.height)> maxArea) { + maxArea = size.width * size.height; + maxSize = size; + } + } + Log.i(TAG, "Max 4:3 -> " + maxSize.width + " x " + maxSize.height); + return maxSize; + } + + /** + * 关闭相机 + */ + private void closeCamera() { + synchronized (this) { + if (mCamera == null) { + return; + } + mCamera.setPreviewCallback(null); + mCamera.stopPreview(); + mCamera.release(); + mCamera = null; + } + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + openCamera(holder); + } + + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + closeCamera(); + } + + + /** + * 计算最大公约数 + * + * @param a + * @param b + * @return 最大公约数 + */ + private int gcd(int a, int b) { + if (b == 0) return a; + return gcd(b, a % b); + } +} diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/view/CircleProgressbar.java b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CircleProgressbar.java new file mode 100644 index 0000000..d0cf03d --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CircleProgressbar.java @@ -0,0 +1,465 @@ +package com.cain.ui.fragment.components.circle.view; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.SweepGradient; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import com.cain.ui.R; + +/** + * Android自定义view实现圆环倒计时 + */ +public class CircleProgressbar extends View { + + /*绘制内部圆*/ + private Paint innerCircle = new Paint(); + /*绘制外部圆*/ + private Paint outerCircle = new Paint(); + private RectF rectF = new RectF(); + /*view的大小*/ + private int width, height; + /*转圈背景和前景宽度*/ + private float backgroundProgressWidth; + private float foregroundProgressWidth; + /*转圈背景和前景默认宽度*/ + private final int DEFAULT_FOREGROUND_PROGRESS_WIDTH = 10; + private final int DEFAULT_BACKGROUND_CIRCLE_WIDTH = 10; + /*转圈背景和前景默认颜色值*/ + private int DEFAULT_BACKGROUND_PROGRESS_COLOR = Color.GRAY; + private int DEFAULT_FOREGROUND_PROGRESS_COLOR = Color.RED; + /*转圈背景和前景颜色值*/ + private int backgroundProgressColor; + private int foregroundProgressColor; + /*触摸时是否可移动*/ + private boolean moveCorrect; + /*顺时针方向*/ + private boolean clockWise; + /*进度*/ + private float progress = 0; + private float maxProgress = 100; + /*起始角度位置*/ + private int startAngle = 0; + /*旋转角度位置*/ + private float sweepAngle = 0; + /*绘制圆的中心点*/ + private int centerPoint; + /*获取转圈背景和前景默认宽度的最大值,为了计算绘制圆的位置*/ + private float subtractingValue; + /*计算绘制外部圆的半径*/ + private float drawRadius; + /*计算内部圆的半径*/ + private float drawOuterRadius; + + /*是否可触摸改变进度*/ + private boolean isTouchEnabled = false; + private boolean roundedCorner; + + /*圆环进度颜色,可设置渐变*/ + private int[] doughnutColors; + /*圆环进度监听*/ + private OnProgressbarChangeListener onProgressbarChangeListener; + + public CircleProgressbar(Context context) { + super(context); + init(); + } + + public CircleProgressbar(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleProgressbar(Context context, AttributeSet attrs, int i) { + super(context, attrs, i); + TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressbar, 0, 0); + backgroundProgressWidth = typeArray.getDimension(R.styleable.CircleProgressbar_cpb_backgroundProgressWidth, DEFAULT_BACKGROUND_CIRCLE_WIDTH); + foregroundProgressWidth = typeArray.getDimension(R.styleable.CircleProgressbar_cpb_foregroundProgressWidth, DEFAULT_FOREGROUND_PROGRESS_WIDTH); + backgroundProgressColor = typeArray.getColor(R.styleable.CircleProgressbar_cpb_backgroundProgressColor, DEFAULT_BACKGROUND_PROGRESS_COLOR); + foregroundProgressColor = typeArray.getColor(R.styleable.CircleProgressbar_cpb_foregroundProgressColor, DEFAULT_FOREGROUND_PROGRESS_COLOR); + this.progress = typeArray.getFloat(R.styleable.CircleProgressbar_cpb_progress, progress); + this.maxProgress = typeArray.getFloat(R.styleable.CircleProgressbar_cpb_maxProgress, maxProgress); + this.roundedCorner = typeArray.getBoolean(R.styleable.CircleProgressbar_cpb_roundedCorner, false); + this.clockWise = typeArray.getBoolean(R.styleable.CircleProgressbar_cpb_clockwise, false); + this.isTouchEnabled = typeArray.getBoolean(R.styleable.CircleProgressbar_cpb_touchEnabled, false); + typeArray.recycle(); + // 圆环默认颜色为主题色,可设置为颜色渐变 + doughnutColors = new int[]{foregroundProgressColor, foregroundProgressColor}; + init(); + if (roundedCorner) { + setRoundedCorner(roundedCorner); + } + if (this.progress> 0) { + setProgress(this.progress); + } + + if (clockWise) { + setClockwise(clockWise); + } + + if (isTouchEnabled) { + enabledTouch(isTouchEnabled); + } + } + + private void init() { + innerCircle.setStrokeWidth(foregroundProgressWidth); //圆环宽度 + innerCircle.setAntiAlias(true); //抗锯齿 + innerCircle.setStyle(Paint.Style.STROKE); //设置图形为空心 + innerCircle.setColor(foregroundProgressColor); //设置颜色 + + outerCircle.setStrokeWidth(backgroundProgressWidth); + outerCircle.setAntiAlias(true); + outerCircle.setColor(backgroundProgressColor); + outerCircle.setStyle(Paint.Style.STROKE); + } + + /** + * 倒计时转圈颜色类型 + * + * @param selectColor 根据各种条件,可变换倒计时圆圈的渐变颜色 + */ + public void setDoughnutColors(int selectColor) { + if (selectColor == 1) { + doughnutColors = new int[]{Color.parseColor("#60B4FD"), Color.parseColor("#5C72F2")}; + } else if (selectColor == 2) { + doughnutColors = new int[]{Color.parseColor("#FCC95C"), Color.parseColor("#FD80A8")}; + } else { + doughnutColors = new int[]{Color.parseColor("#5DC072"), Color.parseColor("#5DC072")}; + } + invalidate(); + } + + // @Override + // protected void onDraw(Canvas canvas) { + // canvas.drawCircle(centerPoint, centerPoint, drawRadius, outerCircle); + // canvas.drawArc(rectF, startAngle, sweepAngle, false, innerCircle); + // super.onDraw(canvas); + // } + + @Override + protected void onDraw(Canvas canvas) { + //画布旋转90度,根据view的中心点进行旋转,使倒计时的开始位置位于view的顶部 + canvas.rotate(-90, width / 2, height / 2); + canvas.drawCircle(centerPoint, centerPoint, drawRadius, outerCircle); + //设置颜色渐变 + SweepGradient sweepGradient = new SweepGradient(centerPoint, centerPoint, doughnutColors, null); + innerCircle.setShader(sweepGradient); + //指定矩阵旋转,处理设置两端为圆角时分开后的颜色问题 + Matrix matrix = new Matrix(); + matrix.postRotate(2); + sweepGradient.setLocalMatrix(matrix); + canvas.drawArc(rectF, startAngle, sweepAngle, false, innerCircle); + super.onDraw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); + height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); + centerPoint = Math.min(width, height); + int min = Math.min(width, height); + setMeasuredDimension(min, min); + setRadiusRect(); + } + + /** + * 测量,主要是计算获得内外转圈的半径,中心点,位置 + */ + private void setRadiusRect() { + centerPoint = Math.min(width, height) / 2; + subtractingValue = (backgroundProgressWidth> foregroundProgressWidth) ? backgroundProgressWidth : foregroundProgressWidth; + float newSeekWidth = subtractingValue / 2; + drawRadius = Math.min((width - subtractingValue) / 2, (height - subtractingValue) / 2); + drawOuterRadius = Math.min((width - newSeekWidth), (height - newSeekWidth)); + rectF.set(subtractingValue / 2, subtractingValue / 2, drawOuterRadius, drawOuterRadius); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (isTouchEnabled) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (onProgressbarChangeListener != null) { + onProgressbarChangeListener.onStartTracking(this); + } + checkForCorrect(event.getX(), event.getY()); + break; + case MotionEvent.ACTION_MOVE: + if (moveCorrect) { + justMove(event.getX(), event.getY()); + } + upgradeProgress(this.progress, true); + + break; + case MotionEvent.ACTION_UP: + if (onProgressbarChangeListener != null) { + onProgressbarChangeListener.onStopTracking(this); + } + moveCorrect = false; + break; + } + return true; + } + return false; + } + + /** + * 更新进度 + * + * @param progress + * @param b + */ + private void upgradeProgress(float progress, boolean b) { + if (progress < 0) { + if (b) { + progress = -progress; + } else { + progress = 0; + } + } + this.progress = (progress <= maxProgress) ? progress : maxProgress; + sweepAngle = (360 * progress / maxProgress); + + if (this.clockWise) { + if (sweepAngle> 0) { + sweepAngle = -sweepAngle; + } + } + if (onProgressbarChangeListener != null) { + onProgressbarChangeListener.onProgressChanged(this, progress, b); + } + invalidate(); + } + + /** + * 触摸时根据坐标获取进度 + * + * @param x + * @param y + */ + private void justMove(float x, float y) { + if (clockWise) { + float degree = (float) Math.toDegrees(Math.atan2(x - centerPoint, centerPoint - y)); + if (degree> 0) { + degree -= 360; + } + sweepAngle = degree; + } else { + float degree = (float) Math.toDegrees(Math.atan2(x - centerPoint, centerPoint - y)); + if (degree < 0) { + degree += 360; + } + + sweepAngle = degree; + } + progress = (sweepAngle * maxProgress / 360); + invalidate(); + } + + /** + * 设置可触摸点击时检查坐标时是否在规定的范围内,是则获取角度从而计算得到进度值 + * + * @param x + * @param y + */ + private void checkForCorrect(float x, float y) { + float distance = (float) Math.sqrt(Math.pow((x - centerPoint), 2) + Math.pow((y - centerPoint), 2)); + if (distance < drawOuterRadius / 2 + subtractingValue && distance> drawOuterRadius / 2 - subtractingValue * 2) { + moveCorrect = true; + if (clockWise) { + float degree = (float) Math.toDegrees(Math.atan2(x - centerPoint, centerPoint - y)); + + if (degree> 0) { + degree -= 360; + } + sweepAngle = degree; + } else { + float degree = (float) Math.toDegrees(Math.atan2(x - centerPoint, centerPoint - y)); + if (degree < 0) { + degree += 360; + } + + sweepAngle = degree; + } + progress = (sweepAngle * maxProgress / 360); + invalidate(); + } + } + + /** + * 设置是顺时针还是逆时针 + * + * @param clockwise + */ + public void setClockwise(boolean clockwise) { + this.clockWise = clockwise; + if (this.clockWise) { + if (sweepAngle> 0) { + sweepAngle = -sweepAngle; + } + } + invalidate(); + } + + /** + * 设置转圈背景的宽度 + * + * @param width + */ + public void setBackgroundProgressWidth(int width) { + this.backgroundProgressWidth = width; + outerCircle.setStrokeWidth(backgroundProgressWidth); + requestLayout(); + invalidate(); + } + + /** + * 设置转圈前景的宽度 + * + * @param width + */ + public void setForegroundProgressWidth(int width) { + this.foregroundProgressWidth = width; + innerCircle.setStrokeWidth(foregroundProgressWidth); + requestLayout(); + invalidate(); + } + + /** + * 设置转圈背景颜色 + * + * @param color + */ + public void setBackgroundProgressColor(int color) { + this.backgroundProgressColor = color; + outerCircle.setColor(color); + requestLayout(); + invalidate(); + } + + /** + * 设置转圈前景颜色 + * + * @param color + */ + public void setForegroundProgressColor(int color) { + this.foregroundProgressColor = color; + innerCircle.setColor(color); + requestLayout(); + invalidate(); + } + + /** + * 设置进度的最大值 + * + * @param maxProgress + */ + public void setMaxProgress(float maxProgress) { + this.maxProgress = maxProgress; + } + + /** + * 返回进度的最大值 + */ + public float getMaxProgress() { + return maxProgress; + } + + /** + * 获取当前进度 + * + * @return + */ + public float getProgress() { + return progress; + } + + /** + * 设置进度 + * + * @param progress + */ + public void setProgress(float progress) { + upgradeProgress(progress, false); + } + + /** + * 设置进度,可以改变进度的渐变颜色 + * + * @param progress + * @param selectColor + */ + public void setProgress(float progress, int selectColor) { + setDoughnutColors(selectColor); + upgradeProgress(progress, false); + } + + /** + * 设置进度的动画和动画时间 + * + * @param progress + * @param duration + */ + public void setProgressWithAnimation(float progress, int duration) { + ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progress", progress); + objectAnimator.setDuration(duration); + //DecelerateInterpolator 渐变的速度 LinearInterpolator 匀速变化 + objectAnimator.setInterpolator(new DecelerateInterpolator()); + objectAnimator.start(); + } + + /** + * 设置可触摸改变进度 + * + * @param enabled + */ + public void enabledTouch(boolean enabled) { + this.isTouchEnabled = enabled; + invalidate(); + } + + /** + * 设置两端为圆角还是矩形 + * + * @param roundedCorner + */ + public void setRoundedCorner(boolean roundedCorner) { + if (roundedCorner) { + //线帽,即画的两端是否带有圆角 + innerCircle.setStrokeCap(Paint.Cap.ROUND); + outerCircle.setStrokeCap(Paint.Cap.ROUND); + } else { + // 线帽,即画的两端是否带有矩形 + innerCircle.setStrokeCap(Paint.Cap.SQUARE); + outerCircle.setStrokeCap(Paint.Cap.SQUARE); + } + invalidate(); + } + + /** + * 进度监听 + * + * @param onProgressbarChangeListener + */ + public void setOnProgressbarChangeListener(OnProgressbarChangeListener onProgressbarChangeListener) { + this.onProgressbarChangeListener = onProgressbarChangeListener; + } + + public interface OnProgressbarChangeListener { + void onProgressChanged(CircleProgressbar circleSeekbar, float progress, boolean fromUser); + + void onStartTracking(CircleProgressbar circleSeekbar); + + void onStopTracking(CircleProgressbar circleSeekbar); + } +} + diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/view/CountDownView.java b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CountDownView.java new file mode 100644 index 0000000..0965d06 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/components/circle/view/CountDownView.java @@ -0,0 +1,272 @@ +package com.cain.ui.fragment.components.circle.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Handler; +import android.os.Message; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; + +import com.cain.ui.R; + + +/** + * 倒计时view 圆形广告倒计时 + * Created by dalong on 2016年11月14日. + */ + +public class CountDownView extends View implements View.OnClickListener { + + //默认文字 + private final String mDefultText="点击跳过"; + //背景颜色 + private int mBackgroundColor; + //圆环颜色 + private int mRoundColor; + //进度颜色 + private int mRoundProgressColor; + //圆环的宽度 + private float mRoundWidth; + //文字 + private String mText; + //文字的大小 + private float mTextSize; + //文字的颜色 + private int mTextColor; + //倒计时的时间 + private int mCountdownTime; + //背景圆画笔 + private Paint mBackgroundPaint; + // 圆环和进度画笔 + private Paint mBorderPaint; + //文字画笔 + private TextPaint mTextPaint; + //文字换行的一个工具类 实现了文本绘制换行处理 + private StaticLayout mStaticLayout; + //中间坐标 + private int centerX,centerY; + //进度值 + private int mRoundProgress; + //一秒添加的度数 + private int mProgressPart; + + + public CountDownView(Context context) { + this(context,null); + } + + public CountDownView(Context context, AttributeSet attrs) { + this(context, attrs,0); + } + + public CountDownView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CountDownView); + mBackgroundColor=typedArray.getColor(R.styleable.CountDownView_backgroundColor, Color.GRAY); + mRoundColor=typedArray.getColor(R.styleable.CountDownView_roundColor,Color.RED); + mRoundProgressColor=typedArray.getColor(R.styleable.CountDownView_roundProgressColor,Color.YELLOW); + mRoundWidth=typedArray.getDimension(R.styleable.CountDownView_roundWidth,15f); + mText=typedArray.getString(R.styleable.CountDownView_text); + mTextSize = typedArray.getDimensionPixelSize(R.styleable.CountDownView_textSize, (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); + mTextColor=typedArray.getColor(R.styleable.CountDownView_textColor,Color.RED); + mCountdownTime=typedArray.getInt(R.styleable.CountDownView_countdownTime,3000); + typedArray.recycle(); + + init(); + } + + private void init() { + if(TextUtils.isEmpty(mText))mText=mDefultText; + setOnClickListener(this); + //求出每秒需要前进的度数 + mProgressPart=360/(mCountdownTime/1000); + mBackgroundPaint = new Paint(); + mBackgroundPaint.setAntiAlias(true); + mBackgroundPaint.setDither(true); + mBackgroundPaint.setColor(mBackgroundColor); + mBackgroundPaint.setStyle(Paint.Style.FILL); + + mBorderPaint = new Paint(); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setDither(true); + mBorderPaint.setStrokeWidth(mRoundWidth); + mBorderPaint.setStyle(Paint.Style.STROKE); + + + + mTextPaint = new TextPaint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setDither(true); + mTextPaint.setColor(mTextColor); + mTextPaint.setTextSize(mTextSize); + mTextPaint.setTextAlign(Paint.Align.CENTER); + + + int textWidth = (int) mTextPaint.measureText(mText.substring(0, (mText.length() + 1) / 2)); + mStaticLayout = new StaticLayout(mText, mTextPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 1F, 0, false); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int widthMode=MeasureSpec.getMode(widthMeasureSpec); + int widthSize=MeasureSpec.getSize(widthMeasureSpec); + int heightMode=MeasureSpec.getMode(heightMeasureSpec); + int heightSize=MeasureSpec.getSize(heightMeasureSpec); + + //如果没有设置宽度就使用文字的宽度来设置 + if (widthMode != MeasureSpec.EXACTLY) { + widthSize = mStaticLayout.getWidth()+getPaddingRight()+getPaddingLeft(); + } + //如果没有设置高度就使用文字的高度来设置 + if (heightMode != MeasureSpec.EXACTLY) { + heightSize = mStaticLayout.getHeight()+getPaddingBottom()+getPaddingTop(); + } + int max=Math.max(widthSize,heightSize); + setMeasuredDimension(max, max); + } + + + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + centerX=getMeasuredWidth()/2; + centerY=getMeasuredHeight()/2; + drawBackground(canvas); + drawRound(canvas); + drawRoundProgress(canvas); + drawText(canvas); + } + + /** + * 绘制背景圆 + * @param canvas + */ + private void drawBackground(Canvas canvas) { + canvas.drawCircle(centerX,centerY,Math.max(centerX,centerY),mBackgroundPaint); + } + + + /** + * 绘制圆环 + * @param canvas + */ + private void drawRound(Canvas canvas) { + mBorderPaint.setColor(mRoundColor); + int min=Math.max(centerX,centerY); + canvas.drawCircle(centerX,centerY,min-mRoundWidth/2,mBorderPaint); + } + + + /** + * 绘制进度条 + * @param canvas + */ + private void drawRoundProgress(Canvas canvas) { + mBorderPaint.setColor(mRoundProgressColor); + int min=Math.min(centerX,centerY); + int radius = (int) (min - mRoundWidth / 2); + RectF rectF = new RectF(centerX -radius,centerY -radius, centerX + radius, centerY + radius); + canvas.drawArc(rectF, 0, mRoundProgress, false, mBorderPaint); + } + + + /** + * 绘制文字 + * @param canvas + */ + private void drawText(Canvas canvas) { + canvas.translate(centerX,centerY- mStaticLayout.getHeight() / 2); + mStaticLayout.draw(canvas); + } + + /** + * 开始倒计时 + */ + public void startCountdown() { + if(mRoundProgress>=360)mRoundProgress=0; + if(mOnCountDownListener!=null)mOnCountDownListener.start(); + if(mHandler!=null)mHandler.sendEmptyMessageDelayed(mMsgWhat,1000); + } + + /** + * 停止倒计时 + */ + public void reSetRoundProgress() { + mRoundProgress=0; + invalidate(); + } + + /** + * 停止倒计时 + */ + public void stopCountdown() { + if(mHandler!=null)mHandler.removeMessages(mMsgWhat); + } + + /** + * 更新进度条 + */ + public final int mMsgWhat=1000; + Handler mHandler=new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what){ + case mMsgWhat: + mRoundProgress+=mProgressPart; + if(mRoundProgress>=360){ + mHandler.removeMessages(mMsgWhat); + if(mOnCountDownListener!=null)mOnCountDownListener.finish(); + }else{ + mHandler.sendEmptyMessageDelayed(mMsgWhat,1000); + } + postInvalidate(); + break; + } + } + }; + + OnCountDownListener mOnCountDownListener; + + /** + * 接口实现 + * @param l + */ + public void setOnCountDownListener(OnCountDownListener l) { + this.mOnCountDownListener=l; + } + + /** + * 点击直接结束 + * @param v + */ + @Override + public void onClick(View v) { + if(mHandler!=null) mHandler.removeMessages(mMsgWhat); + if(mOnCountDownListener!=null)mOnCountDownListener.finish(); + } + + /** + * 倒计时回调接口 + */ + public interface OnCountDownListener{ + void start(); + void finish(); + } + + +} diff --git a/app/src/main/java/com/cain/ui/fragment/components/circle/view/FaceView.java b/app/src/main/java/com/cain/ui/fragment/components/circle/view/FaceView.java new file mode 100644 index 0000000..61d2356 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/components/circle/view/FaceView.java @@ -0,0 +1,454 @@ +package com.cain.ui.fragment.components.circle.view; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.graphics.SweepGradient; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import com.cain.ui.R; +import com.cain.ui.util.ScreenUtils; + + +/** + *

+ * 文件名:	FaceView
+ * 作 者:	zj
+ * 时 间:	2019年1月2日 18:27
+ * 描 述:人脸识别界面UI,这里可以接视频流和UI,也可以单纯作为UI展示
+ * 
+ */ +public class FaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { + private final String TAG = "FaceView"; + private SurfaceHolder mSurfaceHolder; + /** + * 是否可以开始绘制了 + */ + private boolean mStart = false; + /** + * 默认中间圆的半径从0开始 + */ + private float currentRadius = 0; + /** + * 控件的宽度(默认) + */ + private int mViewWidth = 400; + /** + * 控件高度 + */ + private int mViewHeight = 400; + /** + * 中心圆屏幕边距 + */ + private int margin; + /** + * 圆圈画笔 + */ + private Paint mPaint; + /** + * 提示文本 + */ + private String mTipText; + /** + * 提示文本颜色 + */ + private int mTipTextColor; + /** + * 提示文本颜色 + */ + private int mTipTextSize; + /** + * 内圆半径 + */ + private int mRadius; + /** + * 背景弧宽度 + */ + private float mBgArcWidth; + + /** + * 圆心点坐标 + */ + private Point mCenterPoint = new Point(); + /** + * 圆弧边界 + */ + private RectF mBgRectF = new RectF(); + + /** + * 开始角度 + */ + private int mStartAngle = 105; + + /** + * 结束角度 + */ + private int mEndAngle = 330; + + /** + * 圆弧背景画笔 + */ + private Paint mBgArcPaint; + /** + * 提示语画笔 + */ + private Paint mTextPaint; + + /** + * 圆弧画笔 + */ + private Paint mArcPaint; + /** + * 渐变器 + */ + private SweepGradient mSweepGradient; + + /** + * 是否开始 + */ + private boolean isRunning = true; + + /** + * 是否后退 + */ + private boolean isBack = false; + /** + * 绘制速度 + */ + private int speed = 5; + + /** + * 设置默认转动角度0 + */ + float currentAngle = 0; + + public FaceView(Context context) { + this(context, null); + } + + public FaceView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public FaceView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + //获取xml里面的属性值 + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FaceView); + mTipText = array.getString(R.styleable.FaceView_tip_text); + mTipTextColor = array.getColor(R.styleable.FaceView_tip_text_color, Color.WHITE); + mTipTextSize = array.getDimensionPixelSize(R.styleable.FaceView_tip_text_size, ScreenUtils.sp2px(context, 12)); + array.recycle(); + Log.d(TAG, "FaceView构造"); + initHolder(context); + } + + + /** + * 初始化控件View + */ + private void initHolder(Context context) { + //获得SurfaceHolder对象 + mSurfaceHolder = getHolder(); + //设置透明背景 + mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT); + //添加回调 + mSurfaceHolder.addCallback(this); + //显示顶层 + setZOrderOnTop(true); + //防止遮住控件 + setZOrderMediaOverlay(true); + //屏蔽界面焦点 + setFocusable(true); + //保持屏幕长亮 + setKeepScreenOn(true); + + //初始化值 + margin = ScreenUtils.dp2px(context, 60); + mBgArcWidth = ScreenUtils.dp2px(context, 5); + + //初始化画笔 + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setColor(getResources().getColor(R.color.colorAccent)); + mPaint.setStyle(Paint.Style.FILL); + + //绘制文字画笔 + mTextPaint = new Paint(); + mTextPaint.setStyle(Paint.Style.FILL); + mTextPaint.setStrokeWidth(8); + mTextPaint.setColor(mTipTextColor); + mTextPaint.setTextSize(mTipTextSize); + mTextPaint.setTextAlign(Paint.Align.CENTER); + + // 圆弧背景 + mBgArcPaint = new Paint(); + mBgArcPaint.setAntiAlias(true); + mBgArcPaint.setColor(getResources().getColor(R.color.circleBg)); + mBgArcPaint.setStyle(Paint.Style.STROKE); + mBgArcPaint.setStrokeWidth(mBgArcWidth); + mBgArcPaint.setStrokeCap(Paint.Cap.ROUND); + + // 圆弧 + mArcPaint = new Paint(); + mArcPaint.setAntiAlias(true); + mArcPaint.setStyle(Paint.Style.STROKE); + mArcPaint.setStrokeWidth(mBgArcWidth); + mArcPaint.setStrokeCap(Paint.Cap.ROUND); + + //开启线程检测 + new Thread(this).start(); + } + + @Override + public void surfaceCreated(SurfaceHolder surfaceHolder) { + mStart = true; + Log.d(TAG, "surfaceCreated()"); + } + + + @Override + public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { + Log.d(TAG, "surfaceChanged()"); + } + + @Override + public void surfaceDestroyed(SurfaceHolder surfaceHolder) { + mStart = false; + Log.d(TAG, "surfaceDestroyed()"); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + //测量view的宽度 + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + if (widthMode == MeasureSpec.EXACTLY) { + mViewWidth = MeasureSpec.getSize(widthMeasureSpec); + } + + //测量view的高度 + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + if (heightMode == MeasureSpec.EXACTLY) { + mViewHeight = MeasureSpec.getSize(heightMeasureSpec); + } + + setMeasuredDimension(mViewWidth, mViewHeight); + Log.d(TAG, "onMeasure mViewWidth : " + mViewWidth + " mViewHeight : " + mViewHeight); + + //获取圆的相关参数 + mCenterPoint.x = mViewWidth / 2; + mCenterPoint.y = mViewHeight / 2; + + //外环圆的半径 + mRadius = mCenterPoint.x - margin; + + //绘制背景圆弧的边界 + mBgRectF.left = mCenterPoint.x - mRadius - mBgArcWidth / 2; + mBgRectF.top = mCenterPoint.y - mRadius - mBgArcWidth / 2; + mBgRectF.right = mCenterPoint.x + mRadius + mBgArcWidth / 2; + mBgRectF.bottom = mCenterPoint.y + mRadius + mBgArcWidth / 2; + + //进度条颜色 -mStartAngle将位置便宜到原处 + mSweepGradient = new SweepGradient(mCenterPoint.x - mStartAngle, mCenterPoint.y - mStartAngle, getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorPrimaryDark)); + } + + @Override + public void run() { + //循环绘制画面内容 + while (true) { + if (mStart) { + drawView(); + } + } + } + + private void drawView() { + Canvas canvas = null; + try { + //获得canvas对象 + canvas = mSurfaceHolder.lockCanvas(); + //清除画布上面里面的内容 + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + //绘制画布内容 + drawContent(canvas); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (canvas != null) { + //释放canvas锁,并且显示视图 + mSurfaceHolder.unlockCanvasAndPost(canvas); + } + } + } + + /** + * 跟新提示信息 + * + * @param title + */ + public void updateTipsInfo(String title) { + mTipText = title; + } + + private void drawContent(Canvas canvas) { + //防止save()和restore()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响 + canvas.save(); + //先画提示语 + drawHintText(canvas); + //绘制正方形的框内类似人脸识别 +// drawFaceRectTest(canvas); + //绘制人脸识别部分 + drawFaceCircle(canvas); + //画外边进度条 + drawRoundProgress(canvas); + canvas.restore(); + } + + private void drawFaceCircle(Canvas canvas) { + // 圆形,放大效果 + currentRadius += 20; + if (currentRadius> mRadius) + currentRadius = mRadius; + + //设置画板样式 + Path path = new Path(); + //以(400,200)为圆心,半径为100绘制圆 指创建顺时针方向的矩形路径 + path.addCircle(mCenterPoint.x, mCenterPoint.y, currentRadius, Path.Direction.CW); + // 是A形状中不同于B的部分显示出来 + canvas.clipPath(path, Region.Op.DIFFERENCE); + // 半透明背景效果 + canvas.clipRect(0, 0, mViewWidth, mViewHeight); + //绘制背景颜色 + canvas.drawColor(getResources().getColor(R.color.white_ff)); + } + + + /** + * 绘制人脸识别界面进度条 + * + * @param canvas canvas + */ + private void drawRoundProgress(Canvas canvas) { + // 逆时针旋转105度 + canvas.rotate(mStartAngle, mCenterPoint.x, mCenterPoint.y); + // 设置圆环背景 + canvas.drawArc(mBgRectF, 0, mEndAngle, false, mBgArcPaint); + //判断是否正在运行 + if (isRunning) { + if (isBack) { + currentAngle -= speed; + if (currentAngle <= 0) + currentAngle = 0; + } else { + currentAngle += speed; + if (currentAngle>= mEndAngle) + currentAngle = mEndAngle; + } + } + // 设置渐变颜色 + mArcPaint.setShader(mSweepGradient); + canvas.drawArc(mBgRectF, 0, currentAngle, false, mArcPaint); + } + + /** + * 从头位置开始动画 + */ + public void resetPositionStart() { + currentAngle = 0; + isBack = false; + } + + /** + * 动画直接完成 + */ + public void finnishAnimator() { + currentAngle = mEndAngle; + isBack = false; + } + + /** + * 停止动画 + */ + public void pauseAnimator() { + isRunning = false; + } + + /** + * 开始动画 + */ + public void startAnimator() { + isRunning = true; + } + + /** + * 动画回退 + */ + public void backAnimator() { + isRunning = true; + isBack = true; + } + + /** + * 动画前进 + */ + public void forwardAnimator() { + isRunning = true; + isBack = false; + } + + /** + * 绘制人脸识别提示 + * + * @param canvas canvas + */ + private void drawHintText(Canvas canvas) { + //圆视图宽度 (屏幕减去两边距离) + int cameraWidth = mViewWidth - 2 * margin; + //x轴起点(文字背景起点) + int x = margin; + //宽度(提示框背景宽度) + int width = cameraWidth; + //y轴起点 + int y = (int) (mCenterPoint.y - mRadius); + //提示框背景高度 + int height = cameraWidth / 4; + Rect rect = new Rect(x, y, x + width, y + height); + canvas.drawRect(rect, mPaint); + + //计算baseline + Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics(); + float distance = (fontMetrics.bottom - fontMetrics.top) / 4; + float baseline = rect.centerY() + distance; + canvas.drawText(mTipText, rect.centerX(), baseline, mTextPaint); + } + + /** + * 绘制人脸识别矩形区域 + * + * @param canvas canvas + */ + private void drawFaceRectTest(Canvas canvas) { + int cameraWidth = mViewWidth - 2 * margin; + int x = margin + cameraWidth / 6; + int width = cameraWidth * 2 / 3; + int y = mCenterPoint.x + (width / 2); + int height = width; + Rect rect = new Rect(x, y, x + width, y + height); + mPaint.setColor(Color.GREEN); + mPaint.setStyle(Paint.Style.STROKE); + canvas.drawRect(rect, mPaint); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cain/ui/fragment/utils/PermissionTestFragment.java b/app/src/main/java/com/cain/ui/fragment/utils/PermissionTestFragment.java new file mode 100644 index 0000000..9a1daa6 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/utils/PermissionTestFragment.java @@ -0,0 +1,67 @@ +package com.cain.ui.fragment.utils; + +import android.Manifest; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.cain.base.base.BaseFragment; +import com.cain.cpage.annotation.Page; +import com.cain.cpage.enums.CoreAnim; +import com.cain.ui.R; +import com.zyq.easypermission.EasyPermission; + +import butterknife.BindView; + +@Page(name = "PermissionTestFragment", anim = CoreAnim.zoom) +public class PermissionTestFragment extends BaseFragment { + + @BindView(R.id.btn_permission_1) + Button btn1; + + @BindView(R.id.btn_permission_2) + Button btn2; + + @BindView(R.id.btn_permission_3) + Button btn3; + + @BindView(R.id.tv_show) + TextView tvShow1; + + + + @Override + protected int getLayoutId() { + return R.layout.fragment_permission_test; + } + + @Override + protected void initViews() { + + //只检查权限和结果并显示它 + btn1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + boolean b = EasyPermission.build().hasPermission(getActivity(), Manifest.permission.CALL_PHONE); + tvShow1.setText(b ? "允许" : "拒绝"); + + } + }); + + //演示只适用于不需要结果 + btn2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + EasyPermission.build().requestPermission(getActivity(), Manifest.permission.CALL_PHONE); + } + }); + + } + + + + + +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/OneClassFragment.java b/app/src/main/java/com/cain/ui/fragment/writestyle/OneClassFragment.java new file mode 100644 index 0000000..4aac49a --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/OneClassFragment.java @@ -0,0 +1,19 @@ +package com.cain.ui.fragment.writestyle; + +import com.cain.ui.base.BaseUIFragment; + +public class OneClassFragment extends BaseUIFragment { + + + @Override + protected int getLayoutId() { + return 0; + } + + @Override + protected void initViews() { + + } + + +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/WritesIndexFragment.java b/app/src/main/java/com/cain/ui/fragment/writestyle/WritesIndexFragment.java new file mode 100644 index 0000000..39be385 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/WritesIndexFragment.java @@ -0,0 +1,140 @@ +package com.cain.ui.fragment.writestyle; + +import android.util.SparseArray; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.cain.ui.R; +import com.cain.ui.base.BaseModuleFragment; +import com.cain.ui.fragment.components.circle.CameraCircle2Fragment; +import com.cain.ui.fragment.components.circle.CameraCircleFragment; +import com.cain.ui.fragment.components.circle.CameraPreviewFragment; +import com.cain.ui.fragment.components.circle.CountProgressFragment; +import com.cain.util.sub.app.FragmentUtils; + +import butterknife.BindView; + +public class WritesIndexFragment extends BaseModuleFragment { + + @BindView(R.id.btn_1) + Button btn1; + + @BindView(R.id.btn_2) + Button btn2; + + @BindView(R.id.btn_3) + Button btn3; + + @BindView(R.id.btn_4) + Button btn4; + + @BindView(R.id.btn_5) + Button btn5; + + @BindView(R.id.tv_show) + TextView tvShow1; + + private LinearLayout rootView; + private int view_sparse_count = 0; + + private SparseArray sparseArray = new SparseArray(); + + + @Override + protected int getLayoutId() { + return R.layout.fragment_writes_index; + } + + @Override + protected void initViews() { + super.initViews(); + + rootView = (LinearLayout) getRootView(); + //只检查权限和结果并显示它 + btn1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + view_sparse_count++; + switch (view_sparse_count){ + case 1: + initLayout(R.layout.view_sparse_one); + break; + case 2: + initLayout(R.layout.view_sparse_two); + break; + case 3: + view_sparse_count = 0; + initLayout(R.layout.view_sparse_thr); + break; + } + } + }); + + //演示只适用于不需要结果 + btn2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CountProgressFragment countProgressFragment = new CountProgressFragment(); + FragmentUtils.replace(getActivity().getSupportFragmentManager(),countProgressFragment,R.id.fragment_container_components); + } + }); + + btn3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CameraCircleFragment fragment = new CameraCircleFragment(); + FragmentUtils.replace(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components); + + } + }); + + btn4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CameraCircle2Fragment fragment = new CameraCircle2Fragment(); + FragmentUtils.replace(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components); + + } + }); + + btn5.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CameraPreviewFragment fragment = new CameraPreviewFragment(); + FragmentUtils.replace(getActivity().getSupportFragmentManager(),fragment,R.id.fragment_container_components); + + } + }); + + } + + @Override + protected String getPageTitle() { + return "写法集合"; + } + + + private View initLayout(int layoutId) { + int count = rootView.getChildCount(); + if (count == 3) //id 为 要 替换的那个 + rootView.removeViewAt(2); + + /*if (layoutId == R.layout.layout_bluetooth_pair_code || layoutId == R.layout.layout_bluetooth_connect || layoutId == R.layout.layout_fix_key_pwd_igtb) { + rootView.getChildAt(1).setVisibility(View.GONE); + } else { + rootView.getChildAt(1).setVisibility(View.VISIBLE); + }*/ + + View view = sparseArray.get(layoutId); + if (view == null) { + view = getLayoutInflater().from(getContext()).inflate(layoutId, rootView, false); + sparseArray.append(layoutId, view); + } + rootView.addView(view); + return view; + } + + +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/Monitor.java b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/Monitor.java new file mode 100644 index 0000000..6b92107 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/Monitor.java @@ -0,0 +1,11 @@ +package com.cain.ui.fragment.writestyle.doTask; + +import android.accessibilityservice.AccessibilityService; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +public interface Monitor { + + void doTask(AccessibilityService service, AccessibilityEvent event, AccessibilityNodeInfo nodeInfo); + +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/NearbyFriendsMonitor.java b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/NearbyFriendsMonitor.java new file mode 100644 index 0000000..4b1ffbe --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/NearbyFriendsMonitor.java @@ -0,0 +1,29 @@ +package com.cain.ui.fragment.writestyle.doTask; + +import android.accessibilityservice.AccessibilityService; +import android.util.Log; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +public class NearbyFriendsMonitor implements Monitor{ + + + private static String TAG = "NearbyFriendsMonitor-->"; + + static NearbyFriendsMonitor monitor = null; + + public static NearbyFriendsMonitor getInstance() { + if (monitor == null){ + monitor = new NearbyFriendsMonitor(); + } + return monitor; + } + + + @Override + public void doTask(AccessibilityService service, AccessibilityEvent event, AccessibilityNodeInfo nodeInfo) { + + Log.e(TAG,"doTask"); + } + +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/OneKeyService.java b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/OneKeyService.java new file mode 100644 index 0000000..395c5ab --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/OneKeyService.java @@ -0,0 +1,53 @@ +package com.cain.ui.fragment.writestyle.doTask; + +import android.accessibilityservice.AccessibilityService; +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.Intent; +import android.util.Log; +import android.view.accessibility.AccessibilityEvent; + +/** + * + */ +public class OneKeyService extends AccessibilityService { + + private static String TAG = "OneKeyService-->"; + + public OneKeyService() { + } + + + @Override + protected void onServiceConnected() { + super.onServiceConnected(); + Log.e(TAG, "onServiceConnected----"); + AccessibilityServiceInfo config = new AccessibilityServiceInfo(); + Log.e(TAG, "服务开启了"); + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + Log.e(TAG, "onAccessibilityEvent----" + event.toString()); + + if (true){ + SportZanMonitor.getInstance().doTask(this,event,getRootInActiveWindow()); + } + if (true){ + NearbyFriendsMonitor.getInstance().doTask(this,event,getRootInActiveWindow()); + } + + } + + @Override + public void onInterrupt() { + Log.e(TAG, "onInterrupt----"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.e(TAG, "onStartCommand----"); + return super.onStartCommand(intent, flags, startId); + } + + +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/SportZanMonitor.java b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/SportZanMonitor.java new file mode 100644 index 0000000..ee8917e --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/doTask/SportZanMonitor.java @@ -0,0 +1,25 @@ +package com.cain.ui.fragment.writestyle.doTask; + +import android.accessibilityservice.AccessibilityService; +import android.util.Log; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +public class SportZanMonitor implements Monitor{ + + private static String TAG = "MyAccessibilityService-->"; + + static SportZanMonitor monitor = null; + + public static SportZanMonitor getInstance() { + if (monitor == null){ + monitor = new SportZanMonitor(); + } + return monitor; + } + + @Override + public void doTask(AccessibilityService service, AccessibilityEvent event, AccessibilityNodeInfo nodeInfo) { + Log.e(TAG,"doTask"); + } +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItem.java b/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItem.java new file mode 100644 index 0000000..abefc31 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItem.java @@ -0,0 +1,19 @@ +package com.cain.ui.fragment.writestyle.factoryitem; + +/** + * 功能item + */ + +public class FuncItem { + public String funcName; + public String subFuncName; + public int resId; + public boolean isNeedValidate;//是否需要验证 + + public FuncItem(String funcName, String subFuncName, int resId, boolean isNeedValidate) { + this.funcName = funcName; + this.subFuncName = subFuncName; + this.resId = resId; + this.isNeedValidate = isNeedValidate; + } +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItemActivity.java b/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItemActivity.java new file mode 100644 index 0000000..3f30807 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItemActivity.java @@ -0,0 +1,33 @@ +package com.cain.ui.fragment.writestyle.factoryitem; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.annotation.Nullable; + +public class FuncItemActivity extends Activity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + } + + protected void setListener() { + //例子 如下 + /*mAdapter.setOnItemClickListener(new FuncAdapter.OnItemClickListener() { + @Override + public void onItemClick(int position) { + String funcName = FuncItemFactory.getInstance().createFuncItems().get(position).funcName; + switch (funcName) { + case FuncItemFactory.CREAT_ENUMBER: + break; + case FuncItemFactory.QUICK_CONTACTPEOPLE: + break; + case FuncItemFactory.ADD_CONTACTPEOPLE: + break; + } + } + });*/ + } +} diff --git a/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItemFactory.java b/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItemFactory.java new file mode 100644 index 0000000..ad929a5 --- /dev/null +++ b/app/src/main/java/com/cain/ui/fragment/writestyle/factoryitem/FuncItemFactory.java @@ -0,0 +1,48 @@ +package com.cain.ui.fragment.writestyle.factoryitem; + +import java.util.ArrayList; +import java.util.List; + +public class FuncItemFactory { + + private static FuncItemFactory instance; + public static final String CREAT_ENUMBER = "生成手机好友"; + @Deprecated + public static final String SHARE_GROUP = "群组分享"; + public static final String QUICK_CONTACTPEOPLE = "加手机好友"; + public static final String ADD_CONTACTPEOPLE = "自动加手机好友"; + public static final String ADD_NEARPEOPLE = "加附近的人"; + public static final String STOP_ADD_PEOPLE = "停止加好友"; + public static final String FLOW_WINDOW = "显示悬浮窗"; + public static final String VALIDATE = "加人验证信息"; + public static final String FEEDBACK = "意见反馈"; + @Deprecated + public static final String SOFT_VALIDATE = "软件激活"; + public static final String HELP = "帮助"; + + private FuncItemFactory() { + + } + + public static FuncItemFactory getInstance() { + synchronized (FuncItemFactory.class) { + if (instance == null) { + instance = new FuncItemFactory(); + } + } + return instance; + } + + public List createFuncItems() { + List list = new ArrayList() { + { + add(new FuncItem(QUICK_CONTACTPEOPLE, "自动快速添加微信手机好友", 1, false)); + add(new FuncItem(ADD_CONTACTPEOPLE, "自动添加微信手机好友", 2, false)); + add(new FuncItem(ADD_NEARPEOPLE, "自动向微信附近的人打招呼", 3, false)); + add(new FuncItem(STOP_ADD_PEOPLE, "停止加人操作", 4, false)); + } + }; + return list; + } + +} diff --git a/app/src/main/java/com/cain/ui/util/ScreenUtils.java b/app/src/main/java/com/cain/ui/util/ScreenUtils.java new file mode 100644 index 0000000..e4100e8 --- /dev/null +++ b/app/src/main/java/com/cain/ui/util/ScreenUtils.java @@ -0,0 +1,113 @@ +package com.cain.ui.util; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import java.lang.reflect.Field; + +/** + * 尺寸屏幕相关工具类
+ */ +public class ScreenUtils { + /** + * 获状态栏高度 + */ + public static int getStatusBarHeight(Context context) { + int statusBarHeight = 0; + try { + Class clazz = Class.forName("com.android.internal.R$dimen"); + Object obj = clazz.newInstance(); + Field field = clazz.getField("status_bar_height"); + int temp = Integer.parseInt(field.get(obj).toString()); + statusBarHeight = context.getResources().getDimensionPixelSize(temp); + } catch (Exception e) { + e.printStackTrace(); + } + return statusBarHeight; + } + + /** + * 隐藏状态栏 + *

也就是设置全屏,一定要在setContentView之前调用,否则报错

+ *

此方法Activity可以继承AppCompatActivity

+ *

启动的时候状态栏会显示一下再隐藏,比如QQ的欢迎界面

+ *

在配置文件中Activity加属性android:theme="@android:style/Theme.NoTitleBar.Fullscreen"

+ *

如加了以上配置Activity不能继承AppCompatActivity,会报错

+ * + * @param activity activity + */ + public static void hideStatusBar(Activity activity) { + activity.requestWindowFeature(Window.FEATURE_NO_TITLE); + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + /** + * 透明状态栏 setContentView之前调用有效 + *>21 + * + * @param activity + */ + public static void setSystemBarTransparent(Activity activity) { + if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP) { + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + activity.getWindow().setStatusBarColor(Color.TRANSPARENT); + } + //如果布局没有置顶 导致空白问题 + /* else if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT) { + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + }*/ + } + + + public static int getSHeight(Context context) { + DisplayMetrics metrics = new DisplayMetrics(); + ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getMetrics(metrics); + + return metrics.heightPixels; + + } + + public static int getSWidth(Context context) { + DisplayMetrics metrics = new DisplayMetrics(); + ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getMetrics(metrics); + + return metrics.widthPixels; + + } + + /** + * 根据手机的分辨率从dp 到 px(像素) + */ + public static int dp2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 根据手机的分辨率从px 到 dp + */ + public static int px2dp(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * 将sp值转换为px值,保证文字大小不变 + */ + public static int sp2px(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_components.xml b/app/src/main/res/layout/activity_components.xml new file mode 100644 index 0000000..87adfa8 --- /dev/null +++ b/app/src/main/res/layout/activity_components.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/app/src/main/res/layout/activity_expands.xml b/app/src/main/res/layout/activity_expands.xml new file mode 100644 index 0000000..e47ba2b --- /dev/null +++ b/app/src/main/res/layout/activity_expands.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/app/src/main/res/layout/activity_permission_test.xml b/app/src/main/res/layout/activity_permission_test.xml new file mode 100755 index 0000000..86302f3 --- /dev/null +++ b/app/src/main/res/layout/activity_permission_test.xml @@ -0,0 +1,80 @@ + + + + + +