Przeglądaj źródła

init some config

Pq 3 lat temu
rodzic
commit
4ffe233352
42 zmienionych plików z 2591 dodań i 180 usunięć
  1. 1 7
      BaseLibrary/src/main/AndroidManifest.xml
  2. 10 4
      BaseLibrary/src/main/java/com/cooleshow/base/ui/activity/BaseActivity.kt
  3. 9 8
      BaseLibrary/src/main/java/com/cooleshow/base/ui/activity/BaseMvpActivity.kt
  4. 283 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUIDeviceHelper.java
  5. 653 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUIDisplayHelper.java
  6. 110 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUILangHelper.java
  7. 464 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUINotchHelper.java
  8. 475 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUIStatusBarHelper.java
  9. 5 0
      BaseLibrary/src/main/res/drawable/shape_login_bt_bg.xml
  10. 5 0
      BaseLibrary/src/main/res/drawable/shape_login_code_bt_bg.xml
  11. 7 0
      BaseLibrary/src/main/res/values/colors.xml
  12. 31 0
      BaseLibrary/src/main/res/values/dimens.xml
  13. 2 2
      BaseLibrary/src/main/res/values/themes.xml
  14. 1 7
      Provider/src/main/AndroidManifest.xml
  15. 4 4
      Provider/src/main/java/com/cooleshow/provider/common/CommonUtils.kt
  16. 1 0
      Provider/src/main/java/com/cooleshow/provider/router/RouterPath.kt
  17. 2 4
      app/build.gradle
  18. 7 5
      app/src/main/AndroidManifest.xml
  19. 26 13
      app/src/main/java/com/example/cooleshow/uI/activity/MainActivity.kt
  20. 20 0
      app/src/main/java/com/example/cooleshow/uI/activity/splash/SplashActivity.kt
  21. 7 0
      app/src/main/res/layout/ac_splash_layout.xml
  22. 1 1
      app/src/main/res/values-night/themes.xml
  23. 1 1
      app/src/main/res/values/themes.xml
  24. 1 19
      usercenter/build.gradle
  25. 21 0
      usercenter/src/main/AndroidManifest.xml
  26. 0 36
      usercenter/src/main/debug/AndroidManifest.xml
  27. 2 0
      usercenter/src/main/java/com/cooleshow/usercenter/injection/component/UserComponent.kt
  28. 16 0
      usercenter/src/main/java/com/cooleshow/usercenter/presenter/VerifyLoginPresenter.java
  29. 10 0
      usercenter/src/main/java/com/cooleshow/usercenter/presenter/view/IVerifyLoginView.java
  30. 12 8
      usercenter/src/main/java/com/cooleshow/usercenter/ui/activity/LoginActivity.kt
  31. 48 0
      usercenter/src/main/java/com/cooleshow/usercenter/ui/activity/VerifyCodeLoginActivity.java
  32. 0 18
      usercenter/src/main/release/AndroidManifest.xml
  33. BIN
      usercenter/src/main/res/drawable-xhdpi/bg_login_bottom.png
  34. BIN
      usercenter/src/main/res/drawable-xhdpi/bg_login_header.png
  35. BIN
      usercenter/src/main/res/drawable-xxhdpi/bg_login_bottom.png
  36. BIN
      usercenter/src/main/res/drawable-xxhdpi/bg_login_header.png
  37. BIN
      usercenter/src/main/res/drawable-xxhdpi/ic_register_privacy_defult.png
  38. BIN
      usercenter/src/main/res/drawable-xxhdpi/ic_register_privacy_select.png
  39. 6 0
      usercenter/src/main/res/drawable/register_privacy_selector_student.xml
  40. 180 43
      usercenter/src/main/res/layout/activity_login.xml
  41. 161 0
      usercenter/src/main/res/layout/activity_verify_code_login.xml
  42. 9 0
      usercenter/src/main/res/values/strings.xml

+ 1 - 7
BaseLibrary/src/main/AndroidManifest.xml

@@ -2,12 +2,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.cooleshow.base">
 
-    <application
-        android:allowBackup="true"
-        android:icon="@mipmap/ic_launcher"
-        android:label="@string/app_name"
-        android:roundIcon="@mipmap/ic_launcher_round"
-        android:supportsRtl="true"
-        android:theme="@style/Theme.CooleShow" />
+    <application />
 
 </manifest>

+ 10 - 4
BaseLibrary/src/main/java/com/cooleshow/base/ui/activity/BaseActivity.kt

@@ -4,19 +4,26 @@ import android.os.Bundle
 import android.view.View
 import android.widget.FrameLayout
 import com.cooleshow.base.common.AppManager
+import com.cooleshow.base.utils.helper.QMUIStatusBarHelper
 import com.trello.rxlifecycle4.components.support.RxAppCompatActivity
 
 /*
     Activity基类,业务无关
  */
-open class BaseActivity: RxAppCompatActivity() {
+abstract class BaseActivity : RxAppCompatActivity() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-
+        setContentView(getLayoutId())
+        initView();
         AppManager.instance.addActivity(this)
+        QMUIStatusBarHelper.translucent(this)
     }
 
+    protected abstract fun getLayoutId(): Int
+
+    protected abstract fun initView()
+
     override fun onDestroy() {
         super.onDestroy()
 
@@ -24,9 +31,8 @@ open class BaseActivity: RxAppCompatActivity() {
     }
 
 
-
     //获取Window中视图content
-    val contentView:View
+    val contentView: View
         get() {
             val content = findViewById<FrameLayout>(android.R.id.content)
             return content.getChildAt(0)

+ 9 - 8
BaseLibrary/src/main/java/com/cooleshow/base/ui/activity/BaseMvpActivity.kt

@@ -20,13 +20,13 @@ import javax.inject.Inject
 /*
     Activity基类,业务相关
  */
-abstract open class BaseMvpActivity<T : BasePresenter<*>> : BaseActivity(), BaseView {
+abstract class BaseMvpActivity<T : BasePresenter<*>> : BaseActivity(), BaseView {
 
     //Presenter泛型,Dagger注入
     @Inject
     lateinit var mPresenter: T
 
-    lateinit var mActivityComponent:ActivityComponent
+    lateinit var mActivityComponent: ActivityComponent
 
     private lateinit var mLoadingDialog: ProgressLoading
 
@@ -41,20 +41,21 @@ abstract open class BaseMvpActivity<T : BasePresenter<*>> : BaseActivity(), Base
         ARouter.getInstance().inject(this)
     }
 
-
     /*
         Dagger注册
      */
     protected abstract fun injectComponent()
 
+
     /*
         初始Activity Component
      */
     private fun initActivityInjection() {
-        mActivityComponent = DaggerActivityComponent.builder().appComponent((application as BaseApplication).appComponent)
-                .activityModule(ActivityModule(this))
-                .lifecycleProviderModule(LifecycleProviderModule(this))
-                .build()
+        mActivityComponent = DaggerActivityComponent.builder()
+            .appComponent((application as BaseApplication).appComponent)
+            .activityModule(ActivityModule(this))
+            .lifecycleProviderModule(LifecycleProviderModule(this))
+            .build()
 
     }
 
@@ -75,7 +76,7 @@ abstract open class BaseMvpActivity<T : BasePresenter<*>> : BaseActivity(), Base
     /*
         错误信息提示,默认实现
      */
-    override fun onError(text:String) {
+    override fun onError(text: String) {
         showToast(text)
     }
 }

+ 283 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUIDeviceHelper.java

@@ -0,0 +1,283 @@
+/*
+ * Tencent is pleased to support the open source community by making QMUI_Android available.
+ *
+ * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://opensource.org/licenses/MIT
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cooleshow.base.utils.helper;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Environment;
+import android.text.TextUtils;
+import android.util.Log;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import androidx.annotation.Nullable;
+
+/**
+ * @author cginechen
+ * @date 2016-08-11
+ */
+@SuppressLint("PrivateApi")
+public class QMUIDeviceHelper {
+    private final static String TAG = "QMUIDeviceHelper";
+    private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
+    private static final String KEY_FLYME_VERSION_NAME = "ro.build.display.id";
+    private final static String FLYME = "flyme";
+    private final static String ZTEC2016 = "zte c2016";
+    private final static String ZUKZ1 = "zuk z1";
+    private final static String ESSENTIAL = "essential";
+    private final static String MEIZUBOARD[] = {"m9", "M9", "mx", "MX"};
+    private static String sMiuiVersionName;
+    private static String sFlymeVersionName;
+    private static boolean sIsTabletChecked = false;
+    private static boolean sIsTabletValue = false;
+    private static final String BRAND = Build.BRAND.toLowerCase();
+
+    static {
+        Properties properties = new Properties();
+
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+            // android 8.0,读取 /system/uild.prop 会报 permission denied
+            FileInputStream fileInputStream = null;
+            try {
+                fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
+                properties.load(fileInputStream);
+            } catch (Exception e) {
+                Log.i(TAG, "read file error");
+            } finally {
+                QMUILangHelper.close(fileInputStream);
+            }
+        }
+
+        Class<?> clzSystemProperties = null;
+        try {
+            clzSystemProperties = Class.forName("android.os.SystemProperties");
+            Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.class);
+            // miui
+            sMiuiVersionName = getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME);
+            //flyme
+            sFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME);
+        } catch (Exception e) {
+            Log.i(TAG, "read SystemProperties error");
+        }
+    }
+
+    private static boolean _isTablet(Context context) {
+        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >=
+                Configuration.SCREENLAYOUT_SIZE_LARGE;
+    }
+
+    /**
+     * 判断是否为平板设备
+     */
+    public static boolean isTablet(Context context) {
+        if (sIsTabletChecked) {
+            return sIsTabletValue;
+        }
+        sIsTabletValue = _isTablet(context);
+        sIsTabletChecked = true;
+        return sIsTabletValue;
+    }
+
+    /**
+     * 判断是否是flyme系统
+     */
+    public static boolean isFlyme() {
+        return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME);
+    }
+
+    /**
+     * 判断是否是MIUI系统
+     */
+    public static boolean isMIUI() {
+        return !TextUtils.isEmpty(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV5() {
+        return "v5".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV6() {
+        return "v6".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV7() {
+        return "v7".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV8() {
+        return "v8".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV9() {
+        return "v9".equals(sMiuiVersionName);
+    }
+
+    public static boolean isFlymeLowerThan(int majorVersion){
+        return isFlymeLowerThan(majorVersion, 0, 0);
+    }
+
+    public static boolean isFlymeLowerThan(int majorVersion, int minorVersion, int patchVersion) {
+        boolean isLower = false;
+        if (sFlymeVersionName != null && !sFlymeVersionName.equals("")) {
+            try{
+                Pattern pattern = Pattern.compile("(\\d+\\.){2}\\d");
+                Matcher matcher = pattern.matcher(sFlymeVersionName);
+                if (matcher.find()) {
+                    String versionString = matcher.group();
+                    if (versionString.length() > 0) {
+                        String[] version = versionString.split("\\.");
+                        if (version.length >= 1) {
+                            if (Integer.parseInt(version[0]) < majorVersion) {
+                                isLower = true;
+                            }
+                        }
+
+                        if(version.length >= 2 && minorVersion > 0){
+                            if (Integer.parseInt(version[1]) < majorVersion) {
+                                isLower = true;
+                            }
+                        }
+
+                        if(version.length >= 3 && patchVersion > 0){
+                            if (Integer.parseInt(version[2]) < majorVersion) {
+                                isLower = true;
+                            }
+                        }
+                    }
+                }
+            }catch (Throwable ignore){
+
+            }
+        }
+        return isMeizu() && isLower;
+    }
+
+
+    public static boolean isMeizu() {
+        return isPhone(MEIZUBOARD) || isFlyme();
+    }
+
+    /**
+     * 判断是否为小米
+     * https://dev.mi.com/doc/?p=254
+     */
+    public static boolean isXiaomi() {
+        return Build.MANUFACTURER.toLowerCase().equals("xiaomi");
+    }
+
+    public static boolean isVivo() {
+        return BRAND.contains("vivo") || BRAND.contains("bbk");
+    }
+
+    public static boolean isOppo() {
+        return BRAND.contains("oppo");
+    }
+
+    public static boolean isHuawei() {
+        return BRAND.contains("huawei") || BRAND.contains("honor");
+    }
+
+    public static boolean isEssentialPhone(){
+        return BRAND.contains("essential");
+    }
+
+
+    /**
+     * 判断是否为 ZUK Z1 和 ZTK C2016。
+     * 两台设备的系统虽然为 android 6.0,但不支持状态栏icon颜色改变,因此经常需要对它们进行额外判断。
+     */
+    public static boolean isZUKZ1() {
+        final String board = Build.MODEL;
+        return board != null && board.toLowerCase().contains(ZUKZ1);
+    }
+
+    public static boolean isZTKC2016() {
+        final String board = Build.MODEL;
+        return board != null && board.toLowerCase().contains(ZTEC2016);
+    }
+
+    private static boolean isPhone(String[] boards) {
+        final String board = Build.BOARD;
+        if (board == null) {
+            return false;
+        }
+        for (String board1 : boards) {
+            if (board.equals(board1)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断悬浮窗权限(目前主要用户魅族与小米的检测)。
+     */
+    public static boolean isFloatWindowOpAllowed(Context context) {
+        final int version = Build.VERSION.SDK_INT;
+        if (version >= 19) {
+            return checkOp(context, 24);  // 24 是AppOpsManager.OP_SYSTEM_ALERT_WINDOW 的值,该值无法直接访问
+        } else {
+            try {
+                return (context.getApplicationInfo().flags & 1 << 27) == 1 << 27;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+    }
+
+    @TargetApi(19)
+    private static boolean checkOp(Context context, int op) {
+        final int version = Build.VERSION.SDK_INT;
+        if (version >= Build.VERSION_CODES.KITKAT) {
+            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+            try {
+                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
+                int property = (Integer) method.invoke(manager, op,
+                        Binder.getCallingUid(), context.getPackageName());
+                return AppOpsManager.MODE_ALLOWED == property;
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    @Nullable
+    private static String getLowerCaseName(Properties p, Method get, String key) {
+        String name = p.getProperty(key);
+        if (name == null) {
+            try {
+                name = (String) get.invoke(null, key);
+            } catch (Exception ignored) {
+            }
+        }
+        if (name != null) name = name.toLowerCase();
+        return name;
+    }
+}

+ 653 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUIDisplayHelper.java

@@ -0,0 +1,653 @@
+package com.cooleshow.base.utils.helper;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.net.ConnectivityManager;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+/**
+ * @author cginechen
+ * @date 2016-03-17
+ */
+public class QMUIDisplayHelper {
+
+    /**
+     * 屏幕密度,系统源码注释不推荐使用
+     */
+    public static final float DENSITY = Resources.getSystem()
+            .getDisplayMetrics().density;
+    private static final String TAG = "QMUIDisplayHelper";
+
+    /**
+     * 是否有摄像头
+     */
+    private static Boolean sHasCamera = null;
+
+    private static int[] sPortraitRealSizeCache = null;
+    private static int[] sLandscapeRealSizeCache = null;
+
+    /**
+     * 获取 DisplayMetrics
+     *
+     * @return
+     */
+    public static DisplayMetrics getDisplayMetrics(Context context) {
+        return context.getResources().getDisplayMetrics();
+    }
+
+    /**
+     * 把以 dp 为单位的值,转化为以 px 为单位的值
+     *
+     * @param dpValue 以 dp 为单位的值
+     * @return px value
+     */
+    public static int dpToPx(int dpValue) {
+        return (int) (dpValue * DENSITY + 0.5f);
+    }
+
+    /**
+     * 把以 px 为单位的值,转化为以 dp 为单位的值
+     *
+     * @param pxValue 以 px 为单位的值
+     * @return dp值
+     */
+    public static int pxToDp(float pxValue) {
+        return (int) (pxValue / DENSITY + 0.5f);
+    }
+
+    public static float getDensity(Context context) {
+        return context.getResources().getDisplayMetrics().density;
+    }
+
+    public static float getFontDensity(Context context) {
+        return context.getResources().getDisplayMetrics().scaledDensity;
+    }
+
+    /**
+     * 获取屏幕宽度
+     *
+     * @return
+     */
+    public static int getScreenWidth(Context context) {
+        return getDisplayMetrics(context).widthPixels;
+    }
+
+    /**
+     * 获取屏幕高度
+     *
+     * @return
+     */
+    public static int getScreenHeight(Context context) {
+        int screenHeight = getDisplayMetrics(context).heightPixels;
+        if(QMUIDeviceHelper.isXiaomi() && xiaomiNavigationGestureEnabled(context)){
+            screenHeight += getResourceNavHeight(context);
+        }
+        return screenHeight;
+    }
+
+    /**
+     * 获取屏幕的真实宽高
+     *
+     * @param context
+     * @return
+     */
+
+    public static int[] getRealScreenSize(Context context) {
+        if (QMUIDeviceHelper.isEssentialPhone() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            // Essential Phone 8.0版本后,Display size 会根据挖孔屏的设置而得到不同的结果,不能信任 cache
+            return doGetRealScreenSize(context);
+        }
+        int orientation = context.getResources().getConfiguration().orientation;
+        int[] result;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            result = sLandscapeRealSizeCache;
+            if (result == null) {
+                result = doGetRealScreenSize(context);
+                if(result[0] > result[1]){
+                    // the result may be wrong sometimes, do not cache !!!!
+                    sLandscapeRealSizeCache = result;
+                }
+            }
+            return result;
+        } else {
+            result = sPortraitRealSizeCache;
+            if (result == null) {
+                result = doGetRealScreenSize(context);
+                if(result[0] < result[1]){
+                    // the result may be wrong sometimes, do not cache !!!!
+                    sPortraitRealSizeCache = result;
+                }
+            }
+            return result;
+        }
+    }
+
+    private static int[] doGetRealScreenSize(Context context) {
+        int[] size = new int[2];
+        int widthPixels, heightPixels;
+        WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display d = w.getDefaultDisplay();
+        DisplayMetrics metrics = new DisplayMetrics();
+        d.getMetrics(metrics);
+        // since SDK_INT = 1;
+        widthPixels = metrics.widthPixels;
+        heightPixels = metrics.heightPixels;
+        try {
+            // used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
+            widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
+            heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
+        } catch (Exception ignored) {
+        }
+        if (Build.VERSION.SDK_INT >= 17) {
+            try {
+                // used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
+                Point realSize = new Point();
+                d.getRealSize(realSize);
+
+
+                Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
+                widthPixels = realSize.x;
+                heightPixels = realSize.y;
+            } catch (Exception ignored) {
+            }
+        }
+
+        size[0] = widthPixels;
+        size[1] = heightPixels;
+        return size;
+    }
+
+    /**
+     * 剔除挖孔屏等导致的不可用区域后的 width
+     *
+     * @param activity
+     * @return
+     */
+    public static int getUsefulScreenWidth(Activity activity) {
+        return getUsefulScreenWidth(activity, QMUINotchHelper.hasNotch(activity));
+    }
+
+    public static int getUsefulScreenWidth(View view) {
+        return getUsefulScreenWidth(view.getContext(), QMUINotchHelper.hasNotch(view));
+    }
+
+    public static int getUsefulScreenWidth(Context context, boolean hasNotch) {
+        int result = getRealScreenSize(context)[0];
+        int orientation = context.getResources().getConfiguration().orientation;
+        boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;
+        if (!hasNotch) {
+            if (isLandscape && QMUIDeviceHelper.isEssentialPhone()
+                    && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+                // https://arstechnica.com/gadgets/2017/09/essential-phone-review-impressive-for-a-new-company-but-not-competitive/
+                // 这里说挖孔屏是状态栏高度的两倍, 但横屏好像小了一点点
+                result -= 2 * QMUIStatusBarHelper.getStatusbarHeight(context);
+            }
+            return result;
+        }
+        if (isLandscape) {
+            // 华为挖孔屏横屏时,会把整个 window 往后移动,因此,可用区域减小
+            if (QMUIDeviceHelper.isHuawei() && !QMUIDisplayHelper.huaweiIsNotchSetToShowInSetting(context)) {
+                result -= QMUINotchHelper.getNotchSizeInHuawei(context)[1];
+            }
+
+            // TODO vivo 设置-系统导航-导航手势样式-显示手势操作区域 打开的情况下,应该减去手势操作区域的高度,但无API
+            // TODO vivo 设置-显示与亮度-第三方应用显示比例 选为安全区域显示时,整个 window 会移动,应该减去移动区域,但无API
+            // TODO oppo 设置-显示与亮度-应用全屏显示-凹形区域显示控制 关闭是,整个 window 会移动,应该减去移动区域,但无API
+        }
+        return result;
+    }
+
+    /**
+     * 剔除挖孔屏等导致的不可用区域后的 height
+     *
+     * @param activity
+     * @return
+     */
+    public static int getUsefulScreenHeight(Activity activity) {
+        return getUsefulScreenHeight(activity, QMUINotchHelper.hasNotch(activity));
+    }
+
+    public static int getUsefulScreenHeight(View view) {
+        return getUsefulScreenHeight(view.getContext(), QMUINotchHelper.hasNotch(view));
+    }
+
+    private static int getUsefulScreenHeight(Context context, boolean hasNotch) {
+        int result = getRealScreenSize(context)[1];
+        int orientation = context.getResources().getConfiguration().orientation;
+        boolean isPortrait = orientation == Configuration.ORIENTATION_PORTRAIT;
+        if (!hasNotch) {
+            if (isPortrait && QMUIDeviceHelper.isEssentialPhone()
+                    && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+                // https://arstechnica.com/gadgets/2017/09/essential-phone-review-impressive-for-a-new-company-but-not-competitive/
+                // 这里说挖孔屏是状态栏高度的两倍
+                result -= 2 * QMUIStatusBarHelper.getStatusbarHeight(context);
+            }
+            return result;
+        }
+//        if (isPortrait) {
+            // TODO vivo 设置-系统导航-导航手势样式-显示手势操作区域 打开的情况下,应该减去手势操作区域的高度,但无API
+            // TODO vivo 设置-显示与亮度-第三方应用显示比例 选为安全区域显示时,整个 window 会移动,应该减去移动区域,但无API
+            // TODO oppo 设置-显示与亮度-应用全屏显示-凹形区域显示控制 关闭是,整个 window 会移动,应该减去移动区域,但无API
+//        }
+        return result;
+    }
+
+    public static boolean isNavMenuExist(Context context) {
+        //通过判断设备是否有返回键、菜单键(不是虚拟键,是手机屏幕外的按键)来确定是否有navigation bar
+        boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
+        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
+
+        if (!hasMenuKey && !hasBackKey) {
+            // 做任何你需要做的,这个设备有一个导航栏
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 单位转换: dp -> px
+     *
+     * @param dp
+     * @return
+     */
+    public static int dp2px(Context context, int dp) {
+        return (int) (getDensity(context) * dp + 0.5);
+    }
+
+    /**
+     * 单位转换: sp -> px
+     *
+     * @param sp
+     * @return
+     */
+    public static int sp2px(Context context, int sp) {
+        return (int) (getFontDensity(context) * sp + 0.5);
+    }
+
+    /**
+     * 单位转换:px -> dp
+     *
+     * @param px
+     * @return
+     */
+    public static int px2dp(Context context, int px) {
+        return (int) (px / getDensity(context) + 0.5);
+    }
+
+    /**
+     * 单位转换:px -> sp
+     *
+     * @param px
+     * @return
+     */
+    public static int px2sp(Context context, int px) {
+        return (int) (px / getFontDensity(context) + 0.5);
+    }
+
+    /**
+     * 判断是否有状态栏
+     *
+     * @param context
+     * @return
+     */
+    public static boolean hasStatusBar(Context context) {
+        if (context instanceof Activity) {
+            Activity activity = (Activity) context;
+            WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
+            return (attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != WindowManager.LayoutParams.FLAG_FULLSCREEN;
+        }
+        return true;
+    }
+
+    /**
+     * 获取ActionBar高度
+     *
+     * @param context
+     * @return
+     */
+    public static int getActionBarHeight(Context context) {
+        int actionBarHeight = 0;
+        TypedValue tv = new TypedValue();
+        if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
+            actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
+                    context.getResources().getDisplayMetrics());
+        }
+        return actionBarHeight;
+    }
+
+    /**
+     * 获取状态栏高度
+     *
+     * @param context
+     * @return
+     */
+    public static int getStatusBarHeight(Context context) {
+        if(QMUIDeviceHelper.isXiaomi()){
+            int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+            if (resourceId > 0) {
+                return context.getResources().getDimensionPixelSize(resourceId);
+            }
+            return 0;
+        }
+        try {
+            Class<?> c = Class.forName("com.android.internal.R$dimen");
+            Object obj = c.newInstance();
+            Field field = c.getField("status_bar_height");
+            int x = Integer.parseInt(field.get(obj).toString());
+            if(x > 0){
+                return context.getResources().getDimensionPixelSize(x);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    /**
+     * 获取虚拟菜单的高度,若无则返回0
+     *
+     * @param context
+     * @return
+     */
+    public static int getNavMenuHeight(Context context) {
+        if (!isNavMenuExist(context)) {
+            return 0;
+        }
+        int resourceNavHeight = getResourceNavHeight(context);
+        if (resourceNavHeight >= 0) {
+            return resourceNavHeight;
+        }
+
+        // 小米 MIX 有nav bar, 而 getRealScreenSize(context)[1] - getScreenHeight(context) = 0
+        return getRealScreenSize(context)[1] - getScreenHeight(context);
+    }
+
+    private static int getResourceNavHeight(Context context){
+        // 小米4没有nav bar, 而 navigation_bar_height 有值
+        int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
+        if (resourceId > 0) {
+            return context.getResources().getDimensionPixelSize(resourceId);
+        }
+        return -1;
+    }
+
+    public static final boolean hasCamera(Context context) {
+        if (sHasCamera == null) {
+            PackageManager pckMgr = context.getPackageManager();
+            boolean flag = pckMgr
+                    .hasSystemFeature("android.hardware.camera.front");
+            boolean flag1 = pckMgr.hasSystemFeature("android.hardware.camera");
+            boolean flag2;
+            flag2 = flag || flag1;
+            sHasCamera = flag2;
+        }
+        return sHasCamera;
+    }
+
+    /**
+     * 是否有硬件menu
+     *
+     * @param context
+     * @return
+     */
+    @SuppressWarnings("SimplifiableIfStatement")
+    public static boolean hasHardwareMenuKey(Context context) {
+        boolean flag;
+        if (Build.VERSION.SDK_INT < 11)
+            flag = true;
+        else if (Build.VERSION.SDK_INT >= 14) {
+            flag = ViewConfiguration.get(context).hasPermanentMenuKey();
+        } else
+            flag = false;
+        return flag;
+    }
+
+    /**
+     * 是否有网络功能
+     *
+     * @param context
+     * @return
+     */
+    @SuppressLint("MissingPermission")
+    public static boolean hasInternet(Context context) {
+        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        return cm.getActiveNetworkInfo() != null;
+    }
+
+    /**
+     * 判断是否存在pckName包
+     *
+     * @param pckName
+     * @return
+     */
+    public static boolean isPackageExist(Context context, String pckName) {
+        try {
+            PackageInfo pckInfo = context.getPackageManager()
+                    .getPackageInfo(pckName, 0);
+            if (pckInfo != null)
+                return true;
+        } catch (PackageManager.NameNotFoundException ignored) {
+        }
+        return false;
+    }
+
+    /**
+     * 判断 SD Card 是否 ready
+     *
+     * @return
+     */
+    public static boolean isSdcardReady() {
+        return Environment.MEDIA_MOUNTED.equals(Environment
+                .getExternalStorageState());
+    }
+
+    /**
+     * 获取当前国家的语言
+     *
+     * @param context
+     * @return
+     */
+    public static String getCurCountryLan(Context context) {
+        Configuration config = context.getResources().getConfiguration();
+        Locale sysLocale;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            sysLocale = config.getLocales().get(0);
+        } else {
+            //noinspection deprecation
+            sysLocale = config.locale;
+        }
+        return sysLocale.getLanguage()
+                + "-"
+                + sysLocale.getCountry();
+    }
+
+    /**
+     * 判断是否为中文环境
+     *
+     * @param context
+     * @return
+     */
+    public static boolean isZhCN(Context context) {
+        Configuration config = context.getResources().getConfiguration();
+        Locale sysLocale;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            sysLocale = config.getLocales().get(0);
+        } else {
+            //noinspection deprecation
+            sysLocale = config.locale;
+        }
+        String lang = sysLocale.getCountry();
+        return lang.equalsIgnoreCase("CN");
+    }
+
+    /**
+     * 设置全屏
+     *
+     * @param activity
+     */
+    public static void setFullScreen(Activity activity) {
+        Window window = activity.getWindow();
+        window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+    }
+
+    /**
+     * 取消全屏
+     *
+     * @param activity
+     */
+    public static void cancelFullScreen(Activity activity) {
+        Window window = activity.getWindow();
+        window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+        window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+    }
+
+    /**
+     * 判断是否全屏
+     *
+     * @param activity
+     * @return
+     */
+    public static boolean isFullScreen(Activity activity) {
+        WindowManager.LayoutParams params = activity.getWindow().getAttributes();
+        return (params.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN;
+    }
+
+
+    public static boolean isElevationSupported() {
+        return Build.VERSION.SDK_INT >= 21;
+    }
+
+    public static boolean hasNavigationBar(Context context) {
+        boolean hasNav = deviceHasNavigationBar();
+        if (!hasNav) {
+            return false;
+        }
+        if (QMUIDeviceHelper.isVivo()) {
+            return vivoNavigationGestureEnabled(context);
+        }
+        return true;
+    }
+
+    /**
+     * 判断设备是否存在NavigationBar
+     *
+     * @return true 存在, false 不存在
+     */
+    private static boolean deviceHasNavigationBar() {
+        boolean haveNav = false;
+        try {
+            //1.通过WindowManagerGlobal获取windowManagerService
+            // 反射方法:IWindowManager windowManagerService = WindowManagerGlobal.getWindowManagerService();
+            Class<?> windowManagerGlobalClass = Class.forName("android.view.WindowManagerGlobal");
+            Method getWmServiceMethod = windowManagerGlobalClass.getDeclaredMethod("getWindowManagerService");
+            getWmServiceMethod.setAccessible(true);
+            //getWindowManagerService是静态方法,所以invoke null
+            Object iWindowManager = getWmServiceMethod.invoke(null);
+
+            //2.获取windowMangerService的hasNavigationBar方法返回值
+            // 反射方法:haveNav = windowManagerService.hasNavigationBar();
+            Class<?> iWindowManagerClass = iWindowManager.getClass();
+            Method hasNavBarMethod = iWindowManagerClass.getDeclaredMethod("hasNavigationBar");
+            hasNavBarMethod.setAccessible(true);
+            haveNav = (Boolean) hasNavBarMethod.invoke(iWindowManager);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return haveNav;
+    }
+
+    // ====================== Setting ===========================
+    private static final String VIVO_NAVIGATION_GESTURE = "navigation_gesture_on";
+    private static final String HUAWAI_DISPLAY_NOTCH_STATUS = "display_notch_status";
+    private static final String XIAOMI_DISPLAY_NOTCH_STATUS = "force_black";
+    private static final String XIAOMI_FULLSCREEN_GESTURE = "force_fsg_nav_bar";
+
+    /**
+     * 获取vivo手机设置中的"navigation_gesture_on"值,判断当前系统是使用导航键还是手势导航操作
+     *
+     * @param context app Context
+     * @return false 表示使用的是虚拟导航键(NavigationBar), true 表示使用的是手势, 默认是false
+     */
+    public static boolean vivoNavigationGestureEnabled(Context context) {
+        int val = Settings.Secure.getInt(context.getContentResolver(), VIVO_NAVIGATION_GESTURE, 0);
+        return val != 0;
+    }
+
+
+    public static boolean xiaomiNavigationGestureEnabled(Context context) {
+        int val = Settings.Global.getInt(context.getContentResolver(), XIAOMI_FULLSCREEN_GESTURE, 0);
+        return val != 0;
+    }
+
+
+    public static boolean huaweiIsNotchSetToShowInSetting(Context context) {
+        // 0: 默认
+        // 1: 隐藏显示区域
+        int result = Settings.Secure.getInt(context.getContentResolver(), HUAWAI_DISPLAY_NOTCH_STATUS, 0);
+        return result == 0;
+    }
+
+    /**
+     * 全面屏(是否开启全面屏开关 0 关闭  1 开启)
+     *
+     * @param context
+     * @return
+     */
+    @TargetApi(17)
+    public static boolean navigationGestureEnabled(Context context) {
+        int val = Settings.Global.getInt(context.getContentResolver(), getDeviceInfo(), 0);
+        return val != 0;
+    }
+
+    /**
+     * 获取设备信息(目前支持几大主流的全面屏手机,亲测华为、小米、oppo、魅族、vivo都可以)
+     *
+     * @return
+     */
+    public static String getDeviceInfo() {
+        String brand = Build.BRAND;
+        if(TextUtils.isEmpty(brand)) return "navigationbar_is_min";
+
+        if (brand.equalsIgnoreCase("HUAWEI")) {
+            return "navigationbar_is_min";
+        } else if (brand.equalsIgnoreCase("XIAOMI")) {
+            return "force_fsg_nav_bar";
+        } else if (brand.equalsIgnoreCase("VIVO")) {
+            return "navigation_gesture_on";
+        } else if (brand.equalsIgnoreCase("OPPO")) {
+            return "navigation_gesture_on";
+        } else {
+            return "navigationbar_is_min";
+        }
+    }
+
+    @TargetApi(17)
+    public static boolean xiaomiIsNotchSetToShowInSetting(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(), XIAOMI_DISPLAY_NOTCH_STATUS, 0) == 0;
+    }
+}

+ 110 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUILangHelper.java

@@ -0,0 +1,110 @@
+/*
+ * Tencent is pleased to support the open source community by making QMUI_Android available.
+ *
+ * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://opensource.org/licenses/MIT
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cooleshow.base.utils.helper;
+
+
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Locale;
+
+import androidx.annotation.Nullable;
+
+/**
+ * @author cginechen
+ * @date 2016-03-17
+ */
+public class QMUILangHelper {
+
+    /**
+     * 获取数值的位数,例如9返回1,99返回2,999返回3
+     *
+     * @param number 要计算位数的数值,必须>0
+     * @return 数值的位数,若传的参数小于等于0,则返回0
+     */
+    public static int getNumberDigits(int number) {
+        if (number <= 0) return 0;
+        return (int) (Math.log10(number) + 1);
+    }
+
+
+    public static int getNumberDigits(long number) {
+        if (number <= 0) return 0;
+        return (int) (Math.log10(number) + 1);
+    }
+
+
+    public static String formatNumberToLimitedDigits(int number, int maxDigits) {
+        if (getNumberDigits(number) > maxDigits) {
+            StringBuilder result = new StringBuilder();
+            for (int digit = 1; digit <= maxDigits; digit++) {
+                result.append("9");
+            }
+            result.append("+");
+            return result.toString();
+        } else {
+            return String.valueOf(number);
+        }
+    }
+
+    /**
+     * 规范化价格字符串显示的工具类
+     *
+     * @param price 价格
+     * @return 保留两位小数的价格字符串
+     */
+    public static String regularizePrice(float price) {
+        return String.format(Locale.CHINESE, "%.2f", price);
+    }
+
+    /**
+     * 规范化价格字符串显示的工具类
+     *
+     * @param price 价格
+     * @return 保留两位小数的价格字符串
+     */
+    public static String regularizePrice(double price) {
+        return String.format(Locale.CHINESE, "%.2f", price);
+    }
+
+
+    public static boolean isNullOrEmpty(@Nullable CharSequence string) {
+        return string == null || string.length() == 0;
+    }
+
+    public static void close(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static boolean objectEquals(Object a, Object b) {
+        return (a == b) || (a != null && a.equals(b));
+    }
+
+    public static int constrain(int amount, int low, int high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+
+    public static float constrain(float amount, float low, float high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+}

+ 464 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUINotchHelper.java

@@ -0,0 +1,464 @@
+package com.cooleshow.base.utils.helper;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.Surface;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import java.lang.reflect.Method;
+
+public class QMUINotchHelper {
+
+    private static final String TAG = "QMUINotchHelper";
+
+    private static final int NOTCH_IN_SCREEN_VOIO = 0x00000020;
+    private static final String MIUI_NOTCH = "ro.miui.notch";
+    private static Boolean sHasNotch = null;
+    private static Rect sRotation0SafeInset = null;
+    private static Rect sRotation90SafeInset = null;
+    private static Rect sRotation180SafeInset = null;
+    private static Rect sRotation270SafeInset = null;
+    private static int[] sNotchSizeInHawei = null;
+    private static Boolean sHuaweiIsNotchSetToShow = null;
+
+    public static boolean hasNotchInVivo(Context context) {
+        boolean ret = false;
+        try {
+            ClassLoader cl = context.getClassLoader();
+            Class ftFeature = cl.loadClass("android.util.FtFeature");
+            Method[] methods = ftFeature.getDeclaredMethods();
+            if (methods != null) {
+                for (int i = 0; i < methods.length; i++) {
+                    Method method = methods[i];
+                    if (method.getName().equalsIgnoreCase("isFeatureSupport")) {
+                        ret = (boolean) method.invoke(ftFeature, NOTCH_IN_SCREEN_VOIO);
+                        break;
+                    }
+                }
+            }
+        } catch (ClassNotFoundException e) {
+            Log.i(TAG, "hasNotchInVivo ClassNotFoundException");
+        } catch (Exception e) {
+            Log.e(TAG, "hasNotchInVivo Exception");
+        }
+        return ret;
+    }
+
+
+    public static boolean hasNotchInHuawei(Context context) {
+        boolean hasNotch = false;
+        try {
+            ClassLoader cl = context.getClassLoader();
+            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
+            Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
+            hasNotch = (boolean) get.invoke(HwNotchSizeUtil);
+        } catch (ClassNotFoundException e) {
+            Log.i(TAG, "hasNotchInHuawei ClassNotFoundException");
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "hasNotchInHuawei NoSuchMethodException");
+        } catch (Exception e) {
+            Log.e(TAG, "hasNotchInHuawei Exception");
+        }
+        return hasNotch;
+    }
+
+    public static boolean hasNotchInOppo(Context context) {
+        return context.getPackageManager()
+                .hasSystemFeature("com.oppo.feature.screen.heteromorphism");
+    }
+
+    @SuppressLint("PrivateApi")
+    public static boolean hasNotchInXiaomi(Context context) {
+        try {
+            Class spClass = Class.forName("android.os.SystemProperties");
+            Method getMethod = spClass.getDeclaredMethod("getInt", String.class, int.class);
+            getMethod.setAccessible(true);
+            int hasNotch = (int) getMethod.invoke(null, MIUI_NOTCH, 0);
+            return hasNotch == 1;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    public static boolean hasNotch(View view){
+        if (sHasNotch == null) {
+            if(isNotchOfficialSupport()){
+                if(!attachHasOfficialNotch(view)){
+                    return false;
+                }
+            }else {
+                sHasNotch = has3rdNotch(view.getContext());
+            }
+        }
+        return sHasNotch;
+    }
+
+
+    public static boolean hasNotch(Activity activity) {
+        if (sHasNotch == null) {
+            if(isNotchOfficialSupport()){
+                Window window = activity.getWindow();
+                if(window == null){
+                    return false;
+                }
+                View decorView = window.getDecorView();
+                if(decorView == null){
+                    return false;
+                }
+                if(!attachHasOfficialNotch(decorView)){
+                    return false;
+                }
+            }else {
+                sHasNotch = has3rdNotch(activity);
+            }
+        }
+        return sHasNotch;
+    }
+
+    /**
+     *
+     * @param view
+     * @return false indicates the failure to get the result
+     */
+    @TargetApi(28)
+    private static boolean attachHasOfficialNotch(View view){
+        WindowInsets windowInsets = view.getRootWindowInsets();
+        if(windowInsets != null){
+            DisplayCutout displayCutout = windowInsets.getDisplayCutout();
+            sHasNotch = displayCutout != null;
+            return true;
+        }else{
+            // view not attached, do nothing
+            return false;
+        }
+    }
+
+    public static boolean has3rdNotch(Context context){
+        if (QMUIDeviceHelper.isHuawei()) {
+            return hasNotchInHuawei(context);
+        } else if (QMUIDeviceHelper.isVivo()) {
+            return hasNotchInVivo(context);
+        } else if (QMUIDeviceHelper.isOppo()) {
+            return hasNotchInOppo(context);
+        } else if (QMUIDeviceHelper.isXiaomi()) {
+            return hasNotchInXiaomi(context);
+        }
+        return false;
+    }
+
+    public static int getSafeInsetTop(Activity activity) {
+        if (!hasNotch(activity)) {
+            return 0;
+        }
+        return getSafeInsetRect(activity).top;
+    }
+
+    public static int getSafeInsetBottom(Activity activity) {
+        if (!hasNotch(activity)) {
+            return 0;
+        }
+        return getSafeInsetRect(activity).bottom;
+    }
+
+    public static int getSafeInsetLeft(Activity activity) {
+        if (!hasNotch(activity)) {
+            return 0;
+        }
+        return getSafeInsetRect(activity).left;
+    }
+
+    public static int getSafeInsetRight(Activity activity) {
+        if (!hasNotch(activity)) {
+            return 0;
+        }
+        return getSafeInsetRect(activity).right;
+    }
+
+
+    public static int getSafeInsetTop(View view) {
+        if (!hasNotch(view)) {
+            return 0;
+        }
+        return getSafeInsetRect(view).top;
+    }
+
+    public static int getSafeInsetBottom(View view) {
+        if (!hasNotch(view)) {
+            return 0;
+        }
+        return getSafeInsetRect(view).bottom;
+    }
+
+    public static int getSafeInsetLeft(View view) {
+        if (!hasNotch(view)) {
+            return 0;
+        }
+        return getSafeInsetRect(view).left;
+    }
+
+    public static int getSafeInsetRight(View view) {
+        if (!hasNotch(view)) {
+            return 0;
+        }
+        return getSafeInsetRect(view).right;
+    }
+
+
+    private static void clearAllRectInfo() {
+        sRotation0SafeInset = null;
+        sRotation90SafeInset = null;
+        sRotation180SafeInset = null;
+        sRotation270SafeInset = null;
+    }
+
+    private static void clearPortraitRectInfo() {
+        sRotation0SafeInset = null;
+        sRotation180SafeInset = null;
+    }
+
+    private static void clearLandscapeRectInfo() {
+        sRotation90SafeInset = null;
+        sRotation270SafeInset = null;
+    }
+
+    private static Rect getSafeInsetRect(Activity activity) {
+        if(isNotchOfficialSupport()){
+            Rect rect = new Rect();
+            View decorView = activity.getWindow().getDecorView();
+            getOfficialSafeInsetRect(decorView, rect);
+            return rect;
+        }
+        return get3rdSafeInsetRect(activity);
+    }
+
+    private static Rect getSafeInsetRect(View view) {
+        if(isNotchOfficialSupport()){
+            Rect rect = new Rect();
+            getOfficialSafeInsetRect(view, rect);
+            return rect;
+        }
+        return get3rdSafeInsetRect(view.getContext());
+    }
+
+    @TargetApi(28)
+    private static void getOfficialSafeInsetRect(View view, Rect out) {
+        if(view == null){
+            return;
+        }
+        WindowInsets rootWindowInsets = view.getRootWindowInsets();
+        if(rootWindowInsets == null){
+            return;
+        }
+        DisplayCutout displayCutout = rootWindowInsets.getDisplayCutout();
+        if(displayCutout != null){
+            out.set(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(),
+                    displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());
+        }
+    }
+
+    private static Rect get3rdSafeInsetRect(Context context){
+        // 全面屏设置项更改
+        if (QMUIDeviceHelper.isHuawei()) {
+            boolean isHuaweiNotchSetToShow = QMUIDisplayHelper.huaweiIsNotchSetToShowInSetting(context);
+            if (sHuaweiIsNotchSetToShow != null && sHuaweiIsNotchSetToShow != isHuaweiNotchSetToShow) {
+                clearLandscapeRectInfo();
+            }
+            sHuaweiIsNotchSetToShow = isHuaweiNotchSetToShow;
+        }
+        int screenRotation = getScreenRotation(context);
+        if (screenRotation == Surface.ROTATION_90) {
+            if (sRotation90SafeInset == null) {
+                sRotation90SafeInset = getRectInfoRotation90(context);
+            }
+            return sRotation90SafeInset;
+        } else if (screenRotation == Surface.ROTATION_180) {
+            if (sRotation180SafeInset == null) {
+                sRotation180SafeInset = getRectInfoRotation180(context);
+            }
+            return sRotation180SafeInset;
+        } else if (screenRotation == Surface.ROTATION_270) {
+            if (sRotation270SafeInset == null) {
+                sRotation270SafeInset = getRectInfoRotation270(context);
+            }
+            return sRotation270SafeInset;
+        } else {
+            if (sRotation0SafeInset == null) {
+                sRotation0SafeInset = getRectInfoRotation0(context);
+            }
+            return sRotation0SafeInset;
+        }
+    }
+
+    private static Rect getRectInfoRotation0(Context context) {
+        Rect rect = new Rect();
+        if (QMUIDeviceHelper.isVivo()) {
+            // TODO vivo 显示与亮度-第三方应用显示比例
+            rect.top = getNotchHeightInVivo(context);
+            rect.bottom = 0;
+        } else if (QMUIDeviceHelper.isOppo()) {
+            // TODO OPPO 设置-显示-应用全屏显示-凹形区域显示控制
+            rect.top = QMUIStatusBarHelper.getStatusbarHeight(context);
+            rect.bottom = 0;
+        } else if (QMUIDeviceHelper.isHuawei()) {
+            int[] notchSize = getNotchSizeInHuawei(context);
+            rect.top = notchSize[1];
+            rect.bottom = 0;
+        } else if (QMUIDeviceHelper.isXiaomi()) {
+            rect.top = getNotchHeightInXiaomi(context);
+            rect.bottom = 0;
+        }
+        return rect;
+    }
+
+    private static Rect getRectInfoRotation90(Context context) {
+        Rect rect = new Rect();
+        if (QMUIDeviceHelper.isVivo()) {
+            rect.left = getNotchHeightInVivo(context);
+            rect.right = 0;
+        } else if (QMUIDeviceHelper.isOppo()) {
+            rect.left = QMUIStatusBarHelper.getStatusbarHeight(context);
+            rect.right = 0;
+        } else if (QMUIDeviceHelper.isHuawei()) {
+            if (sHuaweiIsNotchSetToShow) {
+                rect.left = getNotchSizeInHuawei(context)[1];
+            } else {
+                rect.left = 0;
+            }
+            rect.right = 0;
+        } else if (QMUIDeviceHelper.isXiaomi()) {
+            rect.left = getNotchHeightInXiaomi(context);
+            rect.right = 0;
+        }
+        return rect;
+    }
+
+    private static Rect getRectInfoRotation180(Context context) {
+        Rect rect = new Rect();
+        if (QMUIDeviceHelper.isVivo()) {
+            rect.top = 0;
+            rect.bottom = getNotchHeightInVivo(context);
+        } else if (QMUIDeviceHelper.isOppo()) {
+            rect.top = 0;
+            rect.bottom = QMUIStatusBarHelper.getStatusbarHeight(context);
+        } else if (QMUIDeviceHelper.isHuawei()) {
+            int[] notchSize = getNotchSizeInHuawei(context);
+            rect.top = 0;
+            rect.bottom = notchSize[1];
+        } else if (QMUIDeviceHelper.isXiaomi()) {
+            rect.top = 0;
+            rect.bottom = getNotchHeightInXiaomi(context);
+        }
+        return rect;
+    }
+
+    private static Rect getRectInfoRotation270(Context context) {
+        Rect rect = new Rect();
+        if (QMUIDeviceHelper.isVivo()) {
+            rect.right = getNotchHeightInVivo(context);
+            rect.left = 0;
+        } else if (QMUIDeviceHelper.isOppo()) {
+            rect.right = QMUIStatusBarHelper.getStatusbarHeight(context);
+            rect.left = 0;
+        } else if (QMUIDeviceHelper.isHuawei()) {
+            if (sHuaweiIsNotchSetToShow) {
+                rect.right = getNotchSizeInHuawei(context)[1];
+            } else {
+                rect.right = 0;
+            }
+            rect.left = 0;
+        } else if (QMUIDeviceHelper.isXiaomi()) {
+            rect.right = getNotchHeightInXiaomi(context);
+            rect.left = 0;
+        }
+        return rect;
+    }
+
+
+    public static int[] getNotchSizeInHuawei(Context context) {
+        if (sNotchSizeInHawei == null) {
+            sNotchSizeInHawei = new int[]{0, 0};
+            try {
+                ClassLoader cl = context.getClassLoader();
+                Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
+                Method get = HwNotchSizeUtil.getMethod("getNotchSize");
+                sNotchSizeInHawei = (int[]) get.invoke(HwNotchSizeUtil);
+            } catch (ClassNotFoundException e) {
+                Log.e(TAG, "getNotchSizeInHuawei ClassNotFoundException");
+            } catch (NoSuchMethodException e) {
+                Log.e(TAG, "getNotchSizeInHuawei NoSuchMethodException");
+            } catch (Exception e) {
+                Log.e(TAG, "getNotchSizeInHuawei Exception");
+            }
+
+        }
+        return sNotchSizeInHawei;
+    }
+
+    public static int getNotchWidthInXiaomi(Context context) {
+        int resourceId = context.getResources().getIdentifier("notch_width", "dimen", "android");
+        if (resourceId > 0) {
+            return context.getResources().getDimensionPixelSize(resourceId);
+        }
+        return -1;
+    }
+
+    public static int getNotchHeightInXiaomi(Context context) {
+        int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
+        if (resourceId > 0) {
+            return context.getResources().getDimensionPixelSize(resourceId);
+        }
+        return QMUIDisplayHelper.getStatusBarHeight(context);
+    }
+
+    public static int getNotchWidthInVivo(Context context){
+        return QMUIDisplayHelper.dp2px(context, 100);
+    }
+
+    public static int getNotchHeightInVivo(Context context){
+        return QMUIDisplayHelper.dp2px(context, 27);
+    }
+
+    /**
+     * this method is private, because we do not need to handle tablet
+     *
+     * @param context
+     * @return
+     */
+    private static int getScreenRotation(Context context) {
+        WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        if (w == null) {
+            return Surface.ROTATION_0;
+        }
+        Display display = w.getDefaultDisplay();
+        if (display == null) {
+            return Surface.ROTATION_0;
+        }
+
+        return display.getRotation();
+    }
+
+    public static boolean isNotchOfficialSupport(){
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+    }
+
+    /**
+     * fitSystemWindows 对小米挖孔屏横屏挖孔区域无效
+     * @param view
+     * @return
+     */
+    public static boolean needFixLandscapeNotchAreaFitSystemWindow(View view){
+       return QMUIDeviceHelper.isXiaomi() && QMUINotchHelper.hasNotch(view);
+    }
+
+}

+ 475 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/helper/QMUIStatusBarHelper.java

@@ -0,0 +1,475 @@
+package com.cooleshow.base.utils.helper;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.IntDef;
+import androidx.core.view.ViewCompat;
+
+/**
+ * @author cginechen
+ * @date 2016-03-27
+ */
+public class QMUIStatusBarHelper {
+
+    private final static int STATUSBAR_TYPE_DEFAULT = 0;
+    private final static int STATUSBAR_TYPE_MIUI = 1;
+    private final static int STATUSBAR_TYPE_FLYME = 2;
+    private final static int STATUSBAR_TYPE_ANDROID6 = 3; // Android 6.0
+    private final static int STATUS_BAR_DEFAULT_HEIGHT_DP = 25; // 大部分状态栏都是25dp
+    // 在某些机子上存在不同的density值,所以增加两个虚拟值
+    public static float sVirtualDensity = -1;
+    public static float sVirtualDensityDpi = -1;
+    private static int sStatusBarHeight = -1;
+    private static @StatusBarType
+    int mStatusBarType = STATUSBAR_TYPE_DEFAULT;
+    private static Integer sTransparentValue;
+
+    public static void translucent(Activity activity) {
+        translucent(activity.getWindow());
+    }
+
+    public static void translucent(Window window) {
+        translucent(window, 0x40000000);
+    }
+
+    private static boolean supportTranslucent() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
+                // Essential Phone 在 Android 8 之前沉浸式做得不全,系统不从状态栏顶部开始布局却会下发 WindowInsets
+                && !(QMUIDeviceHelper.isEssentialPhone() && Build.VERSION.SDK_INT < 26);
+    }
+
+    /**
+     * 沉浸式状态栏。
+     * 支持 4.4 以上版本的 MIUI 和 Flyme,以及 5.0 以上版本的其他 Android。
+     *
+     * @param activity 需要被设置沉浸式状态栏的 Activity。
+     */
+    public static void translucent(Activity activity, @ColorInt int colorOn5x) {
+        Window window = activity.getWindow();
+        translucent(window, colorOn5x);
+    }
+
+    @TargetApi(19)
+    public static void translucent(Window window, @ColorInt int colorOn5x) {
+        if (!supportTranslucent()) {
+            // 版本小于4.4,绝对不考虑沉浸式
+            return;
+        }
+
+        if (QMUINotchHelper.isNotchOfficialSupport()) {
+            handleDisplayCutoutMode(window);
+        }
+
+        // 小米和魅族4.4 以上版本支持沉浸式
+        // 小米 Android 6.0 ,开发版 7.7.13 及以后版本设置黑色字体又需要 clear FLAG_TRANSLUCENT_STATUS, 因此还原为官方模式
+        if (QMUIDeviceHelper.isFlymeLowerThan(8) || (QMUIDeviceHelper.isMIUI() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M)) {
+            window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
+                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            return;
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            int systemUiVisibility = window.getDecorView().getSystemUiVisibility();
+            systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+            window.getDecorView().setSystemUiVisibility(systemUiVisibility);
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && supportTransclentStatusBar6()) {
+                // android 6以后可以改状态栏字体颜色,因此可以自行设置为透明
+                // ZUK Z1是个另类,自家应用可以实现字体颜色变色,但没开放接口
+                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                window.setStatusBarColor(Color.TRANSPARENT);
+            } else {
+                // android 5不能修改状态栏字体颜色,因此直接用FLAG_TRANSLUCENT_STATUS,nexus表现为半透明
+                // 魅族和小米的表现如何?
+                // update: 部分手机运用FLAG_TRANSLUCENT_STATUS时背景不是半透明而是没有背景了。。。。。
+//                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+                // 采取setStatusBarColor的方式,部分机型不支持,那就纯黑了,保证状态栏图标可见
+                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                window.setStatusBarColor(colorOn5x);
+            }
+//        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+//            // android4.4的默认是从上到下黑到透明,我们的背景是白色,很难看,因此只做魅族和小米的
+//        } else if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1){
+//            // 如果app 为白色,需要更改状态栏颜色,因此不能让19一下支持透明状态栏
+//            Window window = activity.getWindow();
+//            Integer transparentValue = getStatusBarAPITransparentValue(activity);
+//            if(transparentValue != null) {
+//                window.getDecorView().setSystemUiVisibility(transparentValue);
+//            }
+        }
+    }
+
+    /**
+     * 如果原本存在某一个flag, 就将它迁移到 out
+     * @param window
+     * @param out
+     * @param type
+     * @return
+     */
+    public static int retainSystemUiFlag(Window window, int out, int type) {
+        int now = window.getDecorView().getSystemUiVisibility();
+        if ((now & type) == type) {
+            out |= type;
+        }
+        return out;
+    }
+
+    @TargetApi(28)
+    private static void handleDisplayCutoutMode(final Window window) {
+        View decorView = window.getDecorView();
+        if (decorView != null) {
+            if (ViewCompat.isAttachedToWindow(decorView)) {
+                realHandleDisplayCutoutMode(window, decorView);
+            } else {
+                decorView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+                    @Override
+                    public void onViewAttachedToWindow(View v) {
+                        v.removeOnAttachStateChangeListener(this);
+                        realHandleDisplayCutoutMode(window, v);
+                    }
+
+                    @Override
+                    public void onViewDetachedFromWindow(View v) {
+
+                    }
+                });
+            }
+        }
+    }
+
+    @TargetApi(28)
+    private static void realHandleDisplayCutoutMode(Window window, View decorView) {
+        if (decorView.getRootWindowInsets() != null &&
+                decorView.getRootWindowInsets().getDisplayCutout() != null) {
+            WindowManager.LayoutParams params = window.getAttributes();
+            params.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+                    .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+            window.setAttributes(params);
+        }
+    }
+
+    /**
+     * 设置状态栏黑色字体图标,
+     * 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android
+     *
+     * @param activity 需要被处理的 Activity
+     */
+    public static boolean setStatusBarLightMode(Activity activity) {
+        if (activity == null) return false;
+        // 无语系列:ZTK C2016只能时间和电池图标变色。。。。
+        if (QMUIDeviceHelper.isZTKC2016()) {
+            return false;
+        }
+
+        if (mStatusBarType != STATUSBAR_TYPE_DEFAULT) {
+            return setStatusBarLightMode(activity, mStatusBarType);
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            if (isMIUICustomStatusBarLightModeImpl() && MIUISetStatusBarLightMode(activity.getWindow(), true)) {
+                mStatusBarType = STATUSBAR_TYPE_MIUI;
+                return true;
+            } else if (FlymeSetStatusBarLightMode(activity.getWindow(), true)) {
+                mStatusBarType = STATUSBAR_TYPE_FLYME;
+                return true;
+            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                Android6SetStatusBarLightMode(activity.getWindow(), true);
+                mStatusBarType = STATUSBAR_TYPE_ANDROID6;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 已知系统类型时,设置状态栏黑色字体图标。
+     * 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android
+     *
+     * @param activity 需要被处理的 Activity
+     * @param type     StatusBar 类型,对应不同的系统
+     */
+    private static boolean setStatusBarLightMode(Activity activity, @StatusBarType int type) {
+        if (type == STATUSBAR_TYPE_MIUI) {
+            return MIUISetStatusBarLightMode(activity.getWindow(), true);
+        } else if (type == STATUSBAR_TYPE_FLYME) {
+            return FlymeSetStatusBarLightMode(activity.getWindow(), true);
+        } else if (type == STATUSBAR_TYPE_ANDROID6) {
+            return Android6SetStatusBarLightMode(activity.getWindow(), true);
+        }
+        return false;
+    }
+
+
+    /**
+     * 设置状态栏白色字体图标
+     * 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android
+     */
+    public static boolean setStatusBarDarkMode(Activity activity) {
+        if (activity == null) return false;
+        if (mStatusBarType == STATUSBAR_TYPE_DEFAULT) {
+            // 默认状态,不需要处理
+            return true;
+        }
+
+        if (mStatusBarType == STATUSBAR_TYPE_MIUI) {
+            return MIUISetStatusBarLightMode(activity.getWindow(), false);
+        } else if (mStatusBarType == STATUSBAR_TYPE_FLYME) {
+            return FlymeSetStatusBarLightMode(activity.getWindow(), false);
+        } else if (mStatusBarType == STATUSBAR_TYPE_ANDROID6) {
+            return Android6SetStatusBarLightMode(activity.getWindow(), false);
+        }
+        return true;
+    }
+
+    /**
+     * 设置状态栏字体图标为深色,Android 6
+     *
+     * @param window 需要设置的窗口
+     * @param light  是否把状态栏字体及图标颜色设置为深色
+     * @return boolean 成功执行返回true
+     */
+    @TargetApi(23)
+    private static boolean Android6SetStatusBarLightMode(Window window, boolean light) {
+        View decorView = window.getDecorView();
+        int systemUi = decorView.getSystemUiVisibility();
+        if (light) {
+            systemUi |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        } else {
+            systemUi ^= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        }
+        decorView.setSystemUiVisibility(systemUi);
+        if (QMUIDeviceHelper.isMIUIV9()) {
+            // MIUI 9 低于 6.0 版本依旧只能回退到以前的方案
+            // https://github.com/Tencent/QMUI_Android/issues/160
+            MIUISetStatusBarLightMode(window, light);
+        }
+        return true;
+    }
+
+    /**
+     * 设置状态栏字体图标为深色,需要 MIUIV6 以上
+     *
+     * @param window 需要设置的窗口
+     * @param light  是否把状态栏字体及图标颜色设置为深色
+     * @return boolean 成功执行返回 true
+     */
+    @SuppressWarnings("unchecked")
+    public static boolean MIUISetStatusBarLightMode(Window window, boolean light) {
+        boolean result = false;
+        if (window != null) {
+            Class clazz = window.getClass();
+            try {
+                int darkModeFlag;
+                Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
+                Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
+                darkModeFlag = field.getInt(layoutParams);
+                Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
+                if (light) {
+                    extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
+                } else {
+                    extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
+                }
+                result = true;
+            } catch (Exception ignored) {
+
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 更改状态栏图标、文字颜色的方案是否是MIUI自家的, MIUI9 && Android 6 之后用回Android原生实现
+     * 见小米开发文档说明:https://dev.mi.com/console/doc/detail?pId=1159
+     */
+    private static boolean isMIUICustomStatusBarLightModeImpl() {
+        if (QMUIDeviceHelper.isMIUIV9() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            return true;
+        }
+        return QMUIDeviceHelper.isMIUIV5() || QMUIDeviceHelper.isMIUIV6() ||
+                QMUIDeviceHelper.isMIUIV7() || QMUIDeviceHelper.isMIUIV8();
+    }
+
+    /**
+     * 设置状态栏图标为深色和魅族特定的文字风格
+     * 可以用来判断是否为 Flyme 用户
+     *
+     * @param window 需要设置的窗口
+     * @param light  是否把状态栏字体及图标颜色设置为深色
+     * @return boolean 成功执行返回true
+     */
+    public static boolean FlymeSetStatusBarLightMode(Window window, boolean light) {
+        boolean result = false;
+        if (window != null) {
+
+            Android6SetStatusBarLightMode(window, light);
+
+            // flyme 在 6.2.0.0A 支持了 Android 官方的实现方案,旧的方案失效
+            // 高版本调用这个出现不可预期的 Bug,官方文档也没有给出完整的高低版本兼容方案
+            if (QMUIDeviceHelper.isFlymeLowerThan(7)) {
+                try {
+                    WindowManager.LayoutParams lp = window.getAttributes();
+                    Field darkFlag = WindowManager.LayoutParams.class
+                            .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
+                    Field meizuFlags = WindowManager.LayoutParams.class
+                            .getDeclaredField("meizuFlags");
+                    darkFlag.setAccessible(true);
+                    meizuFlags.setAccessible(true);
+                    int bit = darkFlag.getInt(null);
+                    int value = meizuFlags.getInt(lp);
+                    if (light) {
+                        value |= bit;
+                    } else {
+                        value &= ~bit;
+                    }
+                    meizuFlags.setInt(lp, value);
+                    window.setAttributes(lp);
+                    result = true;
+                } catch (Exception ignored) {
+
+                }
+            } else if (QMUIDeviceHelper.isFlyme()) {
+                result = true;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 获取是否全屏
+     *
+     * @return 是否全屏
+     */
+    public static boolean isFullScreen(Activity activity) {
+        boolean ret = false;
+        try {
+            WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
+            ret = (attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return ret;
+    }
+
+    /**
+     * API19之前透明状态栏:获取设置透明状态栏的system ui visibility的值,这是部分有提供接口的rom使用的
+     * http://stackoverflow.com/questions/21865621/transparent-status-bar-before-4-4-kitkat
+     */
+    public static Integer getStatusBarAPITransparentValue(Context context) {
+        if (sTransparentValue != null) {
+            return sTransparentValue;
+        }
+        String[] systemSharedLibraryNames = context.getPackageManager()
+                .getSystemSharedLibraryNames();
+        String fieldName = null;
+        for (String lib : systemSharedLibraryNames) {
+            if ("touchwiz".equals(lib)) {
+                fieldName = "SYSTEM_UI_FLAG_TRANSPARENT_BACKGROUND";
+            } else if (lib.startsWith("com.sonyericsson.navigationbar")) {
+                fieldName = "SYSTEM_UI_FLAG_TRANSPARENT";
+            }
+        }
+
+        if (fieldName != null) {
+            try {
+                Field field = View.class.getField(fieldName);
+                if (field != null) {
+                    Class<?> type = field.getType();
+                    if (type == int.class) {
+                        sTransparentValue = field.getInt(null);
+                    }
+                }
+            } catch (Exception ignored) {
+            }
+        }
+        return sTransparentValue;
+    }
+
+    /**
+     * 检测 Android 6.0 是否可以启用 window.setStatusBarColor(Color.TRANSPARENT)。
+     */
+    public static boolean supportTransclentStatusBar6() {
+        return !(QMUIDeviceHelper.isZUKZ1() || QMUIDeviceHelper.isZTKC2016());
+    }
+
+    /**
+     * 获取状态栏的高度。
+     */
+    public static int getStatusbarHeight(Context context) {
+        if (sStatusBarHeight == -1) {
+            initStatusBarHeight(context);
+        }
+        return sStatusBarHeight;
+    }
+
+    private static void initStatusBarHeight(Context context) {
+        Class<?> clazz;
+        Object obj = null;
+        Field field = null;
+        try {
+            clazz = Class.forName("com.android.internal.R$dimen");
+            obj = clazz.newInstance();
+            if (QMUIDeviceHelper.isMeizu()) {
+                try {
+                    field = clazz.getField("status_bar_height_large");
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                }
+            }
+            if (field == null) {
+                field = clazz.getField("status_bar_height");
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        if (field != null && obj != null) {
+            try {
+                int id = Integer.parseInt(field.get(obj).toString());
+                sStatusBarHeight = context.getResources().getDimensionPixelSize(id);
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
+        }
+        if (QMUIDeviceHelper.isTablet(context)
+                && sStatusBarHeight > QMUIDisplayHelper.dp2px(context, STATUS_BAR_DEFAULT_HEIGHT_DP)) {
+            //状态栏高度大于25dp的平板,状态栏通常在下方
+            sStatusBarHeight = 0;
+        } else {
+            if (sStatusBarHeight <= 0) {
+                if (sVirtualDensity == -1) {
+                    sStatusBarHeight = QMUIDisplayHelper.dp2px(context, STATUS_BAR_DEFAULT_HEIGHT_DP);
+                } else {
+                    sStatusBarHeight = (int) (STATUS_BAR_DEFAULT_HEIGHT_DP * sVirtualDensity + 0.5f);
+                }
+            }
+        }
+    }
+
+    public static void setVirtualDensity(float density) {
+        sVirtualDensity = density;
+    }
+
+    public static void setVirtualDensityDpi(float densityDpi) {
+        sVirtualDensityDpi = densityDpi;
+    }
+
+    @IntDef({STATUSBAR_TYPE_DEFAULT, STATUSBAR_TYPE_MIUI, STATUSBAR_TYPE_FLYME, STATUSBAR_TYPE_ANDROID6})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface StatusBarType {
+    }
+
+}

+ 5 - 0
BaseLibrary/src/main/res/drawable/shape_login_bt_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_ff2dc7aa"/>
+    <corners android:radius="39dp"/>
+</shape>

+ 5 - 0
BaseLibrary/src/main/res/drawable/shape_login_code_bt_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_fff5f7fb"/>
+    <corners android:radius="39dp"/>
+</shape>

+ 7 - 0
BaseLibrary/src/main/res/values/colors.xml

@@ -20,4 +20,11 @@
     <color name="text_light_dark">#333333</color>
     <color name="text_normal">#666666</color>
     <color name="transparent">#00000000</color>
+
+    <color name="divide_color">#FFEBEBEB</color>
+    <color name="color_ff2dc7aa">#FF2DC7AA</color>
+    <color name="color_fff5f7fb">#FFF5F7FB</color>
+    <color name="color_ffc1c1c1">#FFC1C1C1</color>
+    <color name="color_999999">#999999</color>
+    <color name="color_2dc7aa">#2DC7AA</color>
 </resources>

+ 31 - 0
BaseLibrary/src/main/res/values/dimens.xml

@@ -19,4 +19,35 @@
     <dimen name="text_middle_size">14sp</dimen>
     <dimen name="text_big_size">16sp</dimen>
     <dimen name="text_large_size">18sp</dimen>
+
+    <dimen name="sp_6">6sp</dimen>
+    <dimen name="sp_7">7sp</dimen>
+    <dimen name="sp_8">8sp</dimen>
+    <dimen name="sp_9">9sp</dimen>
+    <dimen name="sp_10">10sp</dimen>
+    <dimen name="sp_11">11sp</dimen>
+    <dimen name="sp_12">12sp</dimen>
+    <dimen name="sp_13">13sp</dimen>
+    <dimen name="sp_14">14sp</dimen>
+    <dimen name="sp_15">15sp</dimen>
+    <dimen name="sp_16">16sp</dimen>
+    <dimen name="sp_17">17sp</dimen>
+    <dimen name="sp_18">18sp</dimen>
+    <dimen name="sp_19">19sp</dimen>
+    <dimen name="sp_20">20sp</dimen>
+    <dimen name="sp_21">21sp</dimen>
+    <dimen name="sp_22">22sp</dimen>
+    <dimen name="sp_23">23sp</dimen>
+    <dimen name="sp_24">24sp</dimen>
+    <dimen name="sp_25">25sp</dimen>
+    <dimen name="sp_26">26sp</dimen>
+    <dimen name="sp_28">28sp</dimen>
+    <dimen name="sp_30">30sp</dimen>
+    <dimen name="sp_32">32sp</dimen>
+    <dimen name="sp_34">34sp</dimen>
+    <dimen name="sp_36">36sp</dimen>
+    <dimen name="sp_38">38sp</dimen>
+    <dimen name="sp_40">40sp</dimen>
+    <dimen name="sp_42">42sp</dimen>
+    <dimen name="sp_48">48sp</dimen>
 </resources>

+ 2 - 2
BaseLibrary/src/main/res/values/themes.xml

@@ -1,6 +1,6 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Base application theme. -->
-    <style name="Theme.CooleShow" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+    <style name="Theme.CooleShow" parent="Theme.AppCompat.NoActionBar">
         <!-- Primary brand color. -->
         <item name="colorPrimary">@color/purple_500</item>
         <item name="colorPrimaryVariant">@color/purple_700</item>
@@ -10,7 +10,7 @@
         <item name="colorSecondaryVariant">@color/teal_700</item>
         <item name="colorOnSecondary">@color/black</item>
         <!-- Status bar color. -->
-        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+        <item name="android:statusBarColor" tools:targetApi="l">@color/transparent</item>
         <!-- Customize your theme here. -->
     </style>
 </resources>

+ 1 - 7
Provider/src/main/AndroidManifest.xml

@@ -2,12 +2,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.cooleshow.provider">
 
-    <application
-        android:allowBackup="true"
-        android:icon="@mipmap/ic_launcher"
-        android:label="@string/app_name"
-        android:roundIcon="@mipmap/ic_launcher_round"
-        android:supportsRtl="true"
-        android:theme="@style/Theme.CooleShow" />
+    <application />
 
 </manifest>

+ 4 - 4
Provider/src/main/java/com/cooleshow/provider/common/CommonUtils.kt

@@ -8,7 +8,7 @@ import com.cooleshow.provider.router.RouterPath
 /*
     顶级函数,判断是否登录
  */
-fun isLogined():Boolean{
+fun isLogined(): Boolean {
     return AppPrefsUtils.getString(BaseConstant.KEY_SP_TOKEN)!!.isNotEmpty()
 }
 
@@ -16,10 +16,10 @@ fun isLogined():Boolean{
     如果已经登录,进行传入的方法处理
     如果没有登录,进入登录界面
  */
-fun afterLogin(method:()->Unit){
-    if (isLogined()){
+fun afterLogin(method: () -> Unit) {
+    if (isLogined()) {
         method()
-    }else{
+    } else {
         ARouter.getInstance().build(RouterPath.UserCenter.PATH_LOGIN).navigation()
     }
 }

+ 1 - 0
Provider/src/main/java/com/cooleshow/provider/router/RouterPath.kt

@@ -17,6 +17,7 @@ object RouterPath{
     class UserCenter{
         companion object {
             const val PATH_LOGIN = "/userCenter/login"
+            const val PATH_VERIFY_LOGIN = "/userCenter/verifyLogin"
 
         }
     }

+ 2 - 4
app/build.gradle

@@ -21,7 +21,7 @@ android {
         targetSdk 31
         versionCode 1
         versionName "1.0"
-
+        flavorDimensions "app"//多渠道打包维度不同问题
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
 
@@ -53,10 +53,8 @@ dependencies {
 
     implementation project(':Provider')
     implementation project(path: ':BaseLibrary')
+    api project(path: ':usercenter')
 
-    if (isUserModule.toBoolean()){
-        implementation project(path:':usercenter')
-    }
     implementation "com.alibaba:arouter-api:$arouter_api_version"
     kapt "com.alibaba:arouter-compiler:$arouter_api_version"
 }

+ 7 - 5
app/src/main/AndroidManifest.xml

@@ -10,20 +10,22 @@
         android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
-        tools:node="replace"
         android:theme="@style/Theme.CooleShow">
         <activity
-            android:name="com.example.cooleshow.ui.activity.MainActivity"
+            android:name=".uI.activity.splash.SplashActivity"
             android:exported="true">
-
-        </activity>
-        <activity android:name="com.cooleshow.usercenter.ui.activity.LoginActivity" android:exported="true" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity
+            android:name="com.example.cooleshow.ui.activity.MainActivity"
+            android:exported="true">
+
+        </activity>
     </application>
 
 </manifest>

+ 26 - 13
app/src/main/java/com/example/cooleshow/uI/activity/MainActivity.kt

@@ -16,41 +16,54 @@ import java.util.*
 import kotlinx.android.synthetic.main.activity_main.*
 
 @Route(path = RouterPath.APPCenter.PATH_HOME)
-class MainActivity :BaseActivity() {
+class MainActivity : BaseActivity() {
 
 
-    private var pressTime:Long = 0
+    private var pressTime: Long = 0
+
     //Fragment 栈管理
     private val mStack = Stack<Fragment>()
+
     //主界面Fragment
     private val mHomeFragment by lazy { HomeFragment() }
+
     //商品分类Fragment
     private val mCategoryFragment by lazy { MeFragment() }
+
     //购物车Fragment
     private val mCartFragment by lazy { MeFragment() }
+
     //消息Fragment
     private val mMsgFragment by lazy { MeFragment() }
+
     //"我的"Fragment
     private val mMeFragment by lazy { MeFragment() }
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        setContentView(R.layout.activity_main)
         initFragment()
         initBottomNav()
         changeFragment(0)
     }
 
+    override fun getLayoutId(): Int {
+        return R.layout.activity_main;
+    }
+
+    override fun initView() {
+        TODO("Not yet implemented")
+    }
+
     /*
         初始化Fragment栈管理
      */
     private fun initFragment() {
         val manager = supportFragmentManager.beginTransaction()
-        manager.add(R.id.mContaier,mHomeFragment)
-        manager.add(R.id.mContaier,mCategoryFragment)
-        manager.add(R.id.mContaier,mCartFragment)
-        manager.add(R.id.mContaier,mMsgFragment)
-        manager.add(R.id.mContaier,mMeFragment)
+        manager.add(R.id.mContaier, mHomeFragment)
+        manager.add(R.id.mContaier, mCategoryFragment)
+        manager.add(R.id.mContaier, mCartFragment)
+        manager.add(R.id.mContaier, mMsgFragment)
+        manager.add(R.id.mContaier, mMeFragment)
         manager.commit()
 
         mStack.add(mHomeFragment)
@@ -63,8 +76,8 @@ class MainActivity :BaseActivity() {
     /*
         初始化底部导航切换事件
      */
-    private fun initBottomNav(){
-        mBottomNavBar?.setTabSelectedListener(object : BottomNavigationBar.OnTabSelectedListener{
+    private fun initBottomNav() {
+        mBottomNavBar?.setTabSelectedListener(object : BottomNavigationBar.OnTabSelectedListener {
             override fun onTabReselected(position: Int) {
             }
 
@@ -84,7 +97,7 @@ class MainActivity :BaseActivity() {
      */
     private fun changeFragment(position: Int) {
         val manager = supportFragmentManager.beginTransaction()
-        for (fragment in mStack){
+        for (fragment in mStack) {
             manager.hide(fragment)
         }
         manager.show(mStack[position])
@@ -96,10 +109,10 @@ class MainActivity :BaseActivity() {
      */
     override fun onBackPressed() {
         val time = System.currentTimeMillis()
-        if (time - pressTime > 2000){
+        if (time - pressTime > 2000) {
             showToast("再按一次退出程序")
             pressTime = time
-        } else{
+        } else {
             AppManager.instance.exitApp(this)
         }
     }

+ 20 - 0
app/src/main/java/com/example/cooleshow/uI/activity/splash/SplashActivity.kt

@@ -0,0 +1,20 @@
+package com.example.cooleshow.uI.activity.splash
+
+import com.alibaba.android.arouter.launcher.ARouter
+import com.cooleshow.base.ui.activity.BaseActivity
+import com.cooleshow.provider.router.RouterPath
+import com.example.cooleshow.R
+
+
+/**
+ * Author by pq, Date on 2022/4/19.
+ */
+class SplashActivity : BaseActivity() {
+    override fun getLayoutId(): Int {
+        return R.layout.ac_splash_layout
+    }
+
+    override fun initView() {
+        ARouter.getInstance().build(RouterPath.UserCenter.PATH_LOGIN).navigation()
+    }
+}

+ 7 - 0
app/src/main/res/layout/ac_splash_layout.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</LinearLayout>

+ 1 - 1
app/src/main/res/values-night/themes.xml

@@ -1,6 +1,6 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Base application theme. -->
-    <style name="Theme.CooleShow" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+    <style name="Theme.CooleShow" parent="Theme.AppCompat.DayNight.NoActionBar">
         <!-- Primary brand color. -->
         <item name="colorPrimary">@color/purple_200</item>
         <item name="colorPrimaryVariant">@color/purple_700</item>

+ 1 - 1
app/src/main/res/values/themes.xml

@@ -1,6 +1,6 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Base application theme. -->
-    <style name="Theme.CooleShow" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+    <style name="Theme.CooleShow" parent="Theme.AppCompat.Light.NoActionBar">
         <!-- Primary brand color. -->
         <item name="colorPrimary">@color/purple_500</item>
         <item name="colorPrimaryVariant">@color/purple_700</item>

+ 1 - 19
usercenter/build.gradle

@@ -1,13 +1,4 @@
-//plugins {
-//    id 'com.android.application'
-//    id 'org.jetbrains.kotlin.android'
-//}
-
-if (isUserModule.toBoolean()) {
-    apply plugin: 'com.android.library'
-} else {
-    apply plugin: 'com.android.application'
-}
+apply plugin: 'com.android.library'
 apply plugin: 'kotlin-android-extensions'
 apply plugin: 'kotlin-kapt'
 apply plugin: 'org.jetbrains.kotlin.android'
@@ -46,15 +37,6 @@ android {
         }
     }
 
-    sourceSets {
-        main {
-            if (isUserModule.toBoolean()) {
-                manifest.srcFile 'src/main/release/AndroidManifest.xml'
-            } else {
-                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
-            }
-        }
-    }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8

+ 21 - 0
usercenter/src/main/AndroidManifest.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.cooleshow.usercenter">
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+
+    <application>
+
+        <activity
+            android:name=".ui.activity.LoginActivity"
+            android:exported="true">
+        </activity>
+
+        <activity
+            android:name=".ui.activity.VerifyCodeLoginActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:screenOrientation="portrait"/>
+
+    </application>
+</manifest>

+ 0 - 36
usercenter/src/main/debug/AndroidManifest.xml

@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="com.cooleshow.usercenter">
-
-    <application
-        android:name="com.cooleshow.base.common.BaseApplication"
-        android:allowBackup="true"
-        android:label="@string/app_name"
-        android:supportsRtl="true"
-        android:theme="@style/AppTheme"
-        tools:replace="android:theme">
-        <activity android:name=".ui.activity.TestActivity" android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-        <activity
-            android:name=".ui.activity.LoginActivity"
-            android:exported="true">
-            <!--            <intent-filter>-->
-            <!--                <action android:name="android.intent.action.MAIN" />-->
-
-            <!--                <category android:name="android.intent.category.LAUNCHER" />-->
-            <!--            </intent-filter>-->
-        </activity>
-    </application>
-
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
-    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
-
-</manifest>

+ 2 - 0
usercenter/src/main/java/com/cooleshow/usercenter/injection/component/UserComponent.kt

@@ -6,6 +6,7 @@ import com.cooleshow.base.injection.component.ActivityComponent
 import com.cooleshow.usercenter.injection.module.UploadModule
 import com.cooleshow.usercenter.injection.module.UserModule
 import com.cooleshow.usercenter.ui.activity.LoginActivity
+import com.cooleshow.usercenter.ui.activity.VerifyCodeLoginActivity
 
 import dagger.Component
 
@@ -20,6 +21,7 @@ import dagger.Component
 interface UserComponent {
 
     fun inject(activity: LoginActivity)
+    fun inject(activity: VerifyCodeLoginActivity)
 //    fun inject(activity:RegisterActivity)
 //    fun inject(activity:ForgetPwdActivity)
 //    fun inject(activity:ResetPwdActivity)

+ 16 - 0
usercenter/src/main/java/com/cooleshow/usercenter/presenter/VerifyLoginPresenter.java

@@ -0,0 +1,16 @@
+package com.cooleshow.usercenter.presenter;
+
+import com.cooleshow.base.presenter.BasePresenter;
+import com.cooleshow.usercenter.presenter.view.IVerifyLoginView;
+
+import javax.inject.Inject;
+
+
+/**
+ * Author by pq, Date on 2022/4/19.
+ */
+public class VerifyLoginPresenter extends BasePresenter<IVerifyLoginView> {
+    @Inject
+    public VerifyLoginPresenter() {
+    }
+}

+ 10 - 0
usercenter/src/main/java/com/cooleshow/usercenter/presenter/view/IVerifyLoginView.java

@@ -0,0 +1,10 @@
+package com.cooleshow.usercenter.presenter.view;
+
+import com.cooleshow.base.presenter.view.BaseView;
+
+/**
+ * Author by pq, Date on 2022/4/19.
+ */
+public interface IVerifyLoginView extends BaseView {
+
+}

+ 12 - 8
usercenter/src/main/java/com/cooleshow/usercenter/ui/activity/LoginActivity.kt

@@ -1,12 +1,11 @@
 package com.cooleshow.usercenter.ui.activity
 
 import android.os.Bundle
-import android.widget.Button
 import com.alibaba.android.arouter.facade.annotation.Route
 import com.alibaba.android.arouter.launcher.ARouter
 import com.cooleshow.base.ext.onClick
-import com.cooleshow.base.ext.showToast
 import com.cooleshow.base.ui.activity.BaseMvpActivity
+import com.cooleshow.base.utils.helper.QMUIStatusBarHelper
 import com.cooleshow.provider.router.RouterPath
 import com.cooleshow.usercenter.R
 import com.cooleshow.usercenter.data.protocol.UserInfo
@@ -17,14 +16,16 @@ import com.cooleshow.usercenter.presenter.view.LoginView
 import kotlinx.android.synthetic.main.activity_login.*
 
 @Route(path = RouterPath.UserCenter.PATH_LOGIN)
-class LoginActivity : BaseMvpActivity<LoginPresenter>(), LoginView{
+class LoginActivity : BaseMvpActivity<LoginPresenter>(), LoginView {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        setContentView(R.layout.activity_login)
-        initView()
+        QMUIStatusBarHelper.setStatusBarLightMode(this);
     }
 
+    override fun getLayoutId(): Int {
+        return R.layout.activity_login;
+    }
 
     override fun injectComponent() {
         DaggerUserComponent.builder()
@@ -40,10 +41,13 @@ class LoginActivity : BaseMvpActivity<LoginPresenter>(), LoginView{
         TODO("Not yet implemented")
     }
 
-    private fun initView() {
-        mForgetPwdTv.onClick{
-            ARouter.getInstance().build(RouterPath.APPCenter.PATH_HOME).navigation()
+    override fun initView() {
+        tv_login_by_code.onClick {
+            ARouter.getInstance().build(RouterPath.UserCenter.PATH_VERIFY_LOGIN).navigation()
         }
+//        mForgetPwdTv.onClick{
+//            ARouter.getInstance().build(RouterPath.APPCenter.PATH_HOME).navigation()
+//        }
 
 
     }

+ 48 - 0
usercenter/src/main/java/com/cooleshow/usercenter/ui/activity/VerifyCodeLoginActivity.java

@@ -0,0 +1,48 @@
+package com.cooleshow.usercenter.ui.activity;
+
+import android.os.Bundle;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.cooleshow.base.ui.activity.BaseMvpActivity;
+import com.cooleshow.base.utils.helper.QMUIStatusBarHelper;
+import com.cooleshow.provider.router.RouterPath;
+import com.cooleshow.usercenter.R;
+import com.cooleshow.usercenter.injection.component.DaggerUserComponent;
+import com.cooleshow.usercenter.injection.module.UserModule;
+import com.cooleshow.usercenter.presenter.VerifyLoginPresenter;
+import com.cooleshow.usercenter.presenter.view.IVerifyLoginView;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Author by pq, Date on 2022/4/19.
+ */
+@Route(path = RouterPath.UserCenter.PATH_VERIFY_LOGIN)
+public class VerifyCodeLoginActivity extends BaseMvpActivity<VerifyLoginPresenter> implements IVerifyLoginView {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        QMUIStatusBarHelper.setStatusBarLightMode(this);
+    }
+
+    @Override
+    protected int getLayoutId() {
+        return R.layout.activity_verify_code_login;
+    }
+
+    @Override
+    protected void initView() {
+
+    }
+
+    @Override
+    protected void injectComponent() {
+        DaggerUserComponent.builder()
+                .activityComponent(mActivityComponent)
+                .userModule(new UserModule())
+                .build()
+                .inject(this);
+        mPresenter.mView = this;
+    }
+}

+ 0 - 18
usercenter/src/main/release/AndroidManifest.xml

@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.cooleshow.usercenter">
-
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
-    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
-    <application
-        android:allowBackup="true"
-        android:label="@string/app_name"
-        android:supportsRtl="true">
-
-        <activity android:name="com.cooleshow.usercenter.ui.activity.LoginActivity" android:exported="true" />
-    </application>
-
-
-
-</manifest>

BIN
usercenter/src/main/res/drawable-xhdpi/bg_login_bottom.png


BIN
usercenter/src/main/res/drawable-xhdpi/bg_login_header.png


BIN
usercenter/src/main/res/drawable-xxhdpi/bg_login_bottom.png


BIN
usercenter/src/main/res/drawable-xxhdpi/bg_login_header.png


BIN
usercenter/src/main/res/drawable-xxhdpi/ic_register_privacy_defult.png


BIN
usercenter/src/main/res/drawable-xxhdpi/ic_register_privacy_select.png


+ 6 - 0
usercenter/src/main/res/drawable/register_privacy_selector_student.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_register_privacy_defult" android:state_checked="false"/>
+    <item android:drawable="@drawable/ic_register_privacy_select" android:state_checked="true"/>
+    <item android:drawable="@drawable/ic_register_privacy_defult"/>
+</selector>

+ 180 - 43
usercenter/src/main/res/layout/activity_login.xml

@@ -1,48 +1,185 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    style="@style/MatchMatch.Vertical.Common">
-    <com.cooleshow.base.widgets.HeaderBar
-        android:id="@+id/mHeaderBar"
-        style="@style/MatchWrap"
-        app:titleText="登录"
-        app:rightText="注册"
-        />
-    <LinearLayout android:background="@drawable/border_corner_all"
-        android:layout_margin="@dimen/common_margin"
-        style="@style/MatchWrap.Vertical">
-        <EditText android:id="@+id/mMobileEt"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/common_line_height"
-            android:background="@null"
-            android:paddingLeft="@dimen/common_padding_small"
-            android:hint="请输入手机号码"
-            android:drawablePadding="@dimen/common_padding_small"
-            android:inputType="phone"/>
-
-        <View style="@style/DividerFixedHeight"/>
-
-        <EditText android:id="@+id/mPwdEt"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/common_line_height"
-            android:background="@null"
-            android:paddingLeft="@dimen/common_padding_small"
-            android:hint="请输入密码"
-            android:drawablePadding="@dimen/common_padding_small"
-            android:inputType="textPassword"/>
-
-    </LinearLayout>
-
-    <Button
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:background="@color/white">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="@drawable/bg_login_header"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_header_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="35dp"
+        android:layout_marginTop="101dp"
+        android:includeFontPadding="false"
+        android:text="您好, \n欢迎使用酷乐秀"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_26"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_phone_num"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="35dp"
+        android:layout_marginTop="73dp"
+        android:includeFontPadding="false"
+        android:text="@string/phone_num_str"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_18"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_header_title" />
+
+
+    <EditText
+        android:id="@+id/et_phone_num"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/common_line_height"
+        android:layout_marginStart="35dp"
+        android:layout_marginEnd="35dp"
+        android:background="@null"
+        android:hint="@string/please_input_phone_num"
+        android:inputType="phone"
+        android:textColorHint="@color/color_ffc1c1c1"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_phone_num" />
+
+
+    <View
+        android:id="@+id/view_phone_divide"
+        android:layout_width="0dp"
+        android:layout_height="1px"
+        android:layout_marginTop="3dp"
+        android:background="@color/divide_color"
+        app:layout_constraintLeft_toLeftOf="@+id/et_phone_num"
+        app:layout_constraintRight_toRightOf="@+id/et_phone_num"
+        app:layout_constraintTop_toBottomOf="@+id/et_phone_num" />
+
+    <TextView
+        android:id="@+id/tv_password_num"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:includeFontPadding="false"
+        android:text="@string/password_str"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_18"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="@+id/tv_phone_num"
+        app:layout_constraintTop_toBottomOf="@+id/view_phone_divide" />
+
+    <EditText
+        android:id="@+id/et_password"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/common_line_height"
+        android:background="@null"
+        android:drawablePadding="@dimen/common_padding_small"
+        android:hint="@string/please_input_pwd"
+        android:inputType="textPassword"
+        android:paddingLeft="@dimen/common_padding_small"
+        android:textColorHint="@color/color_ffc1c1c1"
+        app:layout_constraintLeft_toLeftOf="@+id/et_phone_num"
+        app:layout_constraintRight_toRightOf="@+id/et_phone_num"
+        app:layout_constraintTop_toBottomOf="@+id/tv_password_num" />
+
+    <View
+        android:id="@+id/view_pw_divide"
+        android:layout_width="0dp"
+        android:layout_height="1px"
+        android:layout_marginTop="3dp"
+        android:background="@color/divide_color"
+        app:layout_constraintLeft_toLeftOf="@+id/et_password"
+        app:layout_constraintRight_toRightOf="@+id/et_password"
+        app:layout_constraintTop_toBottomOf="@+id/et_password" />
+
+    <TextView
         android:id="@+id/mLoginBtn"
-        style="@style/FullBtnStyle"
-        android:text="登录"/>
+        android:layout_width="0dp"
+        android:layout_height="50dp"
+        android:layout_marginStart="35dp"
+        android:layout_marginTop="36dp"
+        android:layout_marginEnd="35dp"
+        android:background="@drawable/shape_login_bt_bg"
+        android:gravity="center"
+        android:text="@string/login_str"
+        android:textColor="@color/white"
+        android:textSize="@dimen/sp_17"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/view_pw_divide" />
 
     <TextView
-        android:id="@+id/mForgetPwdTv"
-        style="@style/WrapWrap"
-        android:textColor="@color/common_blue"
-        android:layout_gravity="right"
-        android:layout_marginRight="@dimen/common_margin"
-        android:text="忘记密码?"/>
-</LinearLayout>
+        android:id="@+id/tv_login_by_code"
+        android:layout_width="0dp"
+        android:layout_height="50dp"
+        android:layout_marginTop="20dp"
+        android:background="@drawable/shape_login_code_bt_bg"
+        android:gravity="center"
+        android:includeFontPadding="false"
+        android:text="@string/login_by_code_str"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_17"
+        app:layout_constraintLeft_toLeftOf="@+id/mLoginBtn"
+        app:layout_constraintRight_toRightOf="@+id/mLoginBtn"
+        app:layout_constraintTop_toBottomOf="@+id/mLoginBtn" />
+
+    <CheckBox
+        android:id="@+id/cb_privacy"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="10dp"
+        android:layout_marginTop="10dp"
+        android:background="@android:color/transparent"
+        android:button="@null"
+        android:drawableStart="@drawable/register_privacy_selector_student"
+        android:drawablePadding="5dp"
+        android:paddingTop="10dp"
+        android:paddingBottom="10dp"
+        android:text="@string/read_privacy_and_agree_str"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12"
+        app:layout_constraintLeft_toLeftOf="@+id/tv_login_by_code"
+        app:layout_constraintTop_toBottomOf="@+id/tv_login_by_code" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:includeFontPadding="false"
+        tools:text="《用户注册协议》和《隐私政策》"
+        android:textColor="@color/color_2dc7aa"
+        android:textSize="@dimen/sp_12"
+        app:layout_constraintBottom_toBottomOf="@+id/cb_privacy"
+        app:layout_constraintLeft_toRightOf="@+id/cb_privacy"
+        app:layout_constraintTop_toTopOf="@+id/cb_privacy" />
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="@drawable/bg_login_bottom"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent" />
+
+    <!--    <TextView-->
+    <!--        android:id="@+id/mForgetPwdTv"-->
+    <!--        style="@style/WrapWrap"-->
+    <!--        android:layout_gravity="right"-->
+    <!--        android:layout_marginRight="@dimen/common_margin"-->
+    <!--        android:text="忘记密码?"-->
+    <!--        android:textColor="@color/common_blue"-->
+    <!--        android:visibility="gone" />-->
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 161 - 0
usercenter/src/main/res/layout/activity_verify_code_login.xml

@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/white">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="@drawable/bg_login_header"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_header_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="35dp"
+        android:layout_marginTop="101dp"
+        android:includeFontPadding="false"
+        android:text="您好, \n欢迎使用酷乐秀"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_26"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_phone_num"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="35dp"
+        android:layout_marginTop="73dp"
+        android:includeFontPadding="false"
+        android:text="@string/phone_num_str"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_18"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_header_title" />
+
+
+    <EditText
+        android:id="@+id/et_phone_num"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/common_line_height"
+        android:layout_marginStart="35dp"
+        android:layout_marginEnd="35dp"
+        android:background="@null"
+        android:hint="@string/please_input_phone_num"
+        android:inputType="phone"
+        android:textColorHint="@color/color_ffc1c1c1"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_phone_num" />
+
+
+    <View
+        android:id="@+id/view_phone_divide"
+        android:layout_width="0dp"
+        android:layout_height="1px"
+        android:layout_marginTop="3dp"
+        android:background="@color/divide_color"
+        app:layout_constraintLeft_toLeftOf="@+id/et_phone_num"
+        app:layout_constraintRight_toRightOf="@+id/et_phone_num"
+        app:layout_constraintTop_toBottomOf="@+id/et_phone_num" />
+
+    <TextView
+        android:id="@+id/tv_login_tip"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="11dp"
+        android:includeFontPadding="false"
+        android:text="未注册的手机号验证后自动创建酷乐秀账号"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12"
+        app:layout_constraintLeft_toLeftOf="@+id/view_phone_divide"
+        app:layout_constraintRight_toRightOf="@+id/view_phone_divide"
+        app:layout_constraintTop_toBottomOf="@+id/view_phone_divide" />
+
+    <TextView
+        android:id="@+id/tv_send_verify_code"
+        android:layout_width="0dp"
+        android:layout_height="50dp"
+        android:layout_marginStart="35dp"
+        android:layout_marginTop="36dp"
+        android:layout_marginEnd="35dp"
+        android:background="@drawable/shape_login_bt_bg"
+        android:gravity="center"
+        android:text="@string/get_verify_code_str"
+        android:textColor="@color/white"
+        android:textSize="@dimen/sp_17"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_login_tip" />
+
+    <TextView
+        android:id="@+id/tv_login_by_code"
+        android:layout_width="0dp"
+        android:layout_height="50dp"
+        android:layout_marginTop="20dp"
+        android:background="@drawable/shape_login_code_bt_bg"
+        android:gravity="center"
+        android:includeFontPadding="false"
+        android:text="@string/login_by_pwd_str"
+        android:textColor="@color/black"
+        android:textSize="@dimen/sp_17"
+        app:layout_constraintLeft_toLeftOf="@+id/tv_send_verify_code"
+        app:layout_constraintRight_toRightOf="@+id/tv_send_verify_code"
+        app:layout_constraintTop_toBottomOf="@+id/tv_send_verify_code" />
+
+    <CheckBox
+        android:id="@+id/cb_privacy"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="10dp"
+        android:layout_marginTop="10dp"
+        android:background="@android:color/transparent"
+        android:button="@null"
+        android:drawableStart="@drawable/register_privacy_selector_student"
+        android:drawablePadding="5dp"
+        android:paddingTop="10dp"
+        android:paddingBottom="10dp"
+        android:text="@string/read_privacy_and_agree_str"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12"
+        app:layout_constraintLeft_toLeftOf="@+id/tv_login_by_code"
+        app:layout_constraintTop_toBottomOf="@+id/tv_login_by_code" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:includeFontPadding="false"
+        android:textColor="@color/color_2dc7aa"
+        android:textSize="@dimen/sp_12"
+        app:layout_constraintBottom_toBottomOf="@+id/cb_privacy"
+        app:layout_constraintLeft_toRightOf="@+id/cb_privacy"
+        app:layout_constraintTop_toTopOf="@+id/cb_privacy"
+        tools:text="《用户注册协议》和《隐私政策》" />
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="@drawable/bg_login_bottom"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent" />
+
+    <!--    <TextView-->
+    <!--        android:id="@+id/mForgetPwdTv"-->
+    <!--        style="@style/WrapWrap"-->
+    <!--        android:layout_gravity="right"-->
+    <!--        android:layout_marginRight="@dimen/common_margin"-->
+    <!--        android:text="忘记密码?"-->
+    <!--        android:textColor="@color/common_blue"-->
+    <!--        android:visibility="gone" />-->
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 9 - 0
usercenter/src/main/res/values/strings.xml

@@ -1,3 +1,12 @@
 <resources>
     <string name="app_name">usercenter</string>
+    <string name="phone_num_str">手机号</string>
+    <string name="password_str">密码</string>
+    <string name="login_str">登录</string>
+    <string name="login_by_code_str">短信登录</string>
+    <string name="login_by_pwd_str">密码登录</string>
+    <string name="please_input_pwd">请输入密码</string>
+    <string name="please_input_phone_num">请输入手机号码</string>
+    <string name="read_privacy_and_agree_str">我已阅读并同意</string>
+    <string name="get_verify_code_str">获取短信验证码</string>
 </resources>