超曲面屏工具類

public final class CurvedScreenUtils {

    private static final String TAG = TagPrefix.HRWIDGET + "CurvedScreenUtils";

    /**
     * 單例
     */
    private static final CurvedScreenUtils INSTANCE = new CurvedScreenUtils();

    /**
     * 應用已做了佈局適配,全面屏會鋪滿屏幕
     */
    private static final int LAYOUT_IN_DISPLAY_SIDE_MODE_ALWAYS = 1;

    private static final String SET_DISPLAY_SIDE_MODE = "setDisplaySideMode";

    private static final String GET_DISPLAY_SIDE_REGION_SAFE_INSETS = "getDisplaySideRegion";

    private static final String GET_SAFE_INSETS = "getSafeInsets";

    private int leftSideWidth = 0;

    private int rightSideWidth = 0;

    private int topSideWidth = 0;

    private int bottomSideWidth = 0;

    private boolean mHasSideWidth;

    /**
     * 工具類,私有構造方法
     */
    private CurvedScreenUtils() {

    }

    /**
     * 獲取單例
     *
     * @return 單例
     */
    public static CurvedScreenUtils getInstance() {
        return INSTANCE;
    }

    /**
     * 獲取間距<br/>
     * 調用方判斷API >=20
     *
     * @param window window
     */
    private void makeSideWidth(final Window window, View view) {
        if (view == null) {
            Logger.w(TAG, "makeSideWidth, view is null!");
        }
        View targetView = view == null ? window.getDecorView() : view;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            targetView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
                @Override
                public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
                    WindowManager.LayoutParams params = window.getAttributes();
                    WindowManagerEx.LayoutParamsEx layoutParamsEx = new WindowManagerEx.LayoutParamsEx(params);
                    Method method = ReflectionUtils
                        .getMethod(layoutParamsEx.getClass(), GET_DISPLAY_SIDE_REGION_SAFE_INSETS, WindowInsets.class);
                    Object object = ReflectionUtils.invoke(method, layoutParamsEx, insets);
                    if (object == null) {
                        // 非超曲面設備
                        Logger.w(TAG, "CurvedScreenUtils, is not curved screen device!");
                    } else {
                        Method method0 = ReflectionUtils.getMethod(object.getClass(), GET_SAFE_INSETS);
                        Object rect = ReflectionUtils.invoke(method0, object);
                        if (rect instanceof Rect) {
                            leftSideWidth = ((Rect) rect).left;
                            topSideWidth = ((Rect) rect).top;
                            rightSideWidth = ((Rect) rect).right;
                            bottomSideWidth = ((Rect) rect).bottom;
                            Logger.i(TAG,
                                "leftSideWidth is: " + leftSideWidth + " ;topSideWidth is: " + topSideWidth
                                    + " ;rightSideWidth is: " + rightSideWidth + " ;bottomSideWidth is: "
                                    + bottomSideWidth);
                        }
                    }
                    return insets;
                }
            });
        }
    }

    /**
     * 初始化展示模式 這裏的view不能用window的decorView,否則會出現展示異常
     *
     * @param window window
     * @param view view
     */
    public void setDisplaySideMode(Window window, View view) {
        if (window == null) {
            Logger.w(TAG, "window is null!");
            return;
        }

        Logger.d(TAG, "Emui version is: " + EmuiUtils.VERSION.EMUI_SDK_INT);

        // 如果版本低於EMUI10,那麼直接返回無需適配
        if (!EmuiUtils.isEMUI10xorHigher()) {
            Logger.w(TAG, "Emui version is too low, do not need curved screen settings!");
            return;
        }
        try {
            // 設置曲面屏相關參數
            makeCurvedScreenSettings(window);

            // 獲取間距只需要第一次調用,以後都使用緩存
            if (!mHasSideWidth) {
                Logger.i(TAG, "setDisplaySideMode, makeSideWidth");
                mHasSideWidth = true;

                // 獲取間距
                makeSideWidth(window, view);
            }
        } catch (RuntimeException e) {
            Logger.e(TAG, "makeCurvedScreenSettings caused RuntimeException");
        } catch (Exception e) {
            Logger.e(TAG, "makeCurvedScreenSettings failed");
        }
    }

    /**
     * 初始化展示模式 只傳入window可能導致的異常:界面全部充滿屏幕可能會和底部的導航欄重合
     *
     * @param window window
     */
    public void setDisplaySideMode(Window window) {
        setDisplaySideMode(window, null);
    }

    private void makeCurvedScreenSettings(Window window) {
        try {
            Logger.i(TAG, "makeCurvedScreenSettings!");
            WindowManager.LayoutParams params = window.getAttributes();
            WindowManagerEx.LayoutParamsEx layoutParamsEx = new WindowManagerEx.LayoutParamsEx(params);
            Method method = ReflectionUtils.getMethod(layoutParamsEx.getClass(), SET_DISPLAY_SIDE_MODE, int.class);
            if (null != method) {
                ReflectionUtils.invoke(method, layoutParamsEx, LAYOUT_IN_DISPLAY_SIDE_MODE_ALWAYS);
                setAttributes(window, params);
            }
        } catch (RuntimeException e) {
            Logger.e(TAG, "makeCurvedScreenSettings failed");
        } catch (Exception e) {
            Logger.e(TAG, "makeCurvedScreenSettings failed");
        }
    }

    private void setAttributes(Window window, WindowManager.LayoutParams params) {
        if (window != null && params != null) {
            window.setAttributes(params);
        }
    }

    /**
     * 該方法會修改view左右間距爲#getInstance()#getLeftSideWidth() 長度
     * 原來view的左右間距/margin會被覆蓋,特別處理需要自己修改,非超曲面屏不會對view修改
     * @param padding 是否是內邊距padding,否則是margin
     * @param views 需要設置的view
     */
    public static void offsetViewEdge(boolean padding, View... views) {
        if (views != null) {
            int oldStart = INSTANCE.getLeftSideWidth();
            int oldEnd = INSTANCE.getRightSideWidth();
            // 沒有邊距,非超曲面屏
            if (oldStart == 0 && oldEnd == 0) {
                return;
            }
            for (View view : views) {
                if (view == null) {
                    Logger.w(TAG, "view is null continue next view");
                    continue;
                }
                if (padding) {
                    view.setPadding(INSTANCE.getLeftSideWidth(),
                        view.getPaddingTop(),
                        INSTANCE.getRightSideWidth(),
                        view.getPaddingBottom());
                } else {
                    ViewGroup.MarginLayoutParams lp =
                        ViewUtils.getLayoutParams(view, ViewGroup.MarginLayoutParams.class);
                    if (lp != null) {
                        int oldTop = lp.topMargin;
                        int oldBottom = lp.bottomMargin;
                        lp.setMarginStart(oldStart);
                        lp.topMargin = oldTop;
                        lp.setMarginEnd(oldEnd);
                        lp.bottomMargin = oldBottom;
                        ViewUtils.setLayoutParams(view, lp);
                    }
                }
            }
        }
    }

    /**
     * 獲取左邊距
     *
     * @return 左邊距
     */
    public int getLeftSideWidth() {
        return MultiWindowUtils.isInMultiWindowMode() ? 0 : leftSideWidth;
    }

    /**
     * 獲取界面左間距(含曲面屏動態邊距)
     *
     * @return 左邊距
     */
    public int getPageCommonPaddingStart() {
        return getLeftSideWidth() + ResUtils.getDimensionPixelSize(R.dimen.page_common_padding_start);
    }

    /**
     * 獲取界面右間距(含曲面屏動態邊距)
     *
     * @return 右邊距
     */
    public int getPageCommonPaddingEnd() {
        return getRightSideWidth() + ResUtils.getDimensionPixelSize(R.dimen.page_common_padding_start);
    }

    /**
     * 獲取右邊距
     *
     * @return 右邊距
     */
    public int getRightSideWidth() {
        return MultiWindowUtils.isInMultiWindowMode() ? 0 : rightSideWidth;
    }

    /**
     * 獲取上邊距
     *
     * @return 上邊距
     */
    public int getTopSideWidth() {
        return MultiWindowUtils.isInMultiWindowMode() ? 0 : topSideWidth;
    }

    /**
     * 獲取下邊距
     *
     * @return 下邊距
     */
    public int getBottomSideWidth() {
        return MultiWindowUtils.isInMultiWindowMode() ? 0 : bottomSideWidth;
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章