当前位置: 首页 > news >正文

遥控器控制nefflix优化

优化profile界面焦点问题

JoyarHelper.java

 if (mIsInNf) {
            DisplayMetrics metrice = thiz.getContext().getResources().getDisplayMetrics();
            Rect tmpRect = new Rect();
            thiz.getFocusedRect(tmpRect);
            if (metrice.widthPixels == tmpRect.width() 
                && metrice.heightPixels == tmpRect.height()) {
                if (DBG) {
                    Log.d(TAG, "cause a match full screen view, sould skip it?");
                }
                return true;
            } else if ((tmpRect.width() == 0 || tmpRect.height() == 0) && !isInstanceOfClass(thiz, mNfImgVCls)) {
                if (DBG) {
                    Log.d(TAG, "cause width or height is 0, sould skip it?");
                }
                return true;
            }
        }
        return false;
    }

优化上下移动是否可见判断

JoyarHelper.java

                if (DBG) {
                    Log.d(TAG, "cause width or height is 0, sould skip it?");
                }
                return true;
            }
        }
        return false;
    }

    public void ViewOnDraw(View thiz, Canvas canvas, Rect rect) {
        if (DBG) {
            Log.d(TAG, "ViewOnDraw view:" + thiz + " canvas:" + canvas);
        }

        //Log.d(TAG, "ViewOnDraw isInTouchApp:" + mIsInTouchApp + " isFocused:" + thiz.isFocused() + " rect:" + rect);
        if (mIsInTouchApp && thiz.isFocused()) {
            final int cornerSquareSize = dipsToPixels(thiz, DRAW_CORNERS_SIZE_DIP);
            final int strokeWidthSize = dipsToPixels(thiz, DRAW_STROKE_WIDTH_SIZE_DIP);
            Rect focusedRect = new Rect();
            if (thiz instanceof EditText && rect != null) {
                focusedRect = rect;
            } else if (thiz instanceof AdapterView) {
                View selected = ((AdapterView)thiz).getSelectedView();
                if (DBG) {
                    Log.d(TAG, "get a adapter view:" + thiz + " selected view:" + selected);
                }
                if (selected != null) {
                    selected.getDrawingRect(focusedRect);
                    ((AdapterView)thiz).offsetDescendantRectToMyCoords(selected, focusedRect);
                    if (DBG) {
                        Log.d(TAG, "get selected view rect:" + focusedRect);
                    }
                }
            } else {
                if (mIsInDp) {
                    thiz.getFocusedRect(focusedRect);
                } else {
                    thiz.getDrawingRect(focusedRect);
                }
            }

            boolean isNfImgV = isInstanceOfClass(thiz, mNfImgVCls);
            int strokeWidth = JoyarHelper.DBG 
                ? SystemProperties.getInt("persist.joyar.stroke", DRAW_STROKE_WIDTH_SIZE_DIP) 
                : DRAW_STROKE_WIDTH_SIZE_DIP;

            Paint paint = getDebugPaint();
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(dipsToPixels(thiz, 
                isNfImgV ? strokeWidth * 3 : strokeWidth));

            Shader linearGradient = new LinearGradient(
                    focusedRect.left, focusedRect.top, // 渐变起点
                    focusedRect.right, focusedRect.bottom, // 渐变终点
                    Color.RED, Color.BLUE, // 渐变颜色
                    Shader.TileMode.CLAMP // 边缘模式
            );

            paint.setShader(linearGradient);

            canvas.drawRect(focusedRect, paint);
        }
    }

    private boolean isInstanceOfClass(View view, String name) {
            if (view == null) {
                return false;
            }
            
            Class<?> cls = view.getClass();
            
            for (; cls != Object.class; cls = cls.getSuperclass()) {
                if (name.equals(cls.getSimpleName())) {
                    if (DBG) {
                        Log.d(TAG, "############found isInstanceOfClass class:" + cls + " ############");
                    }
                    return true;
                }
            }
            return false;
        }

    
    public void ViewAddPerformClickViews(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewAddPerformClickViews view:" + thiz);
        }

        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mTagsTextCls) || thiz instanceof TextView) {
                thiz.setFocusable(false);
                thiz.setFocusableInTouchMode(false);
            } else if (isInstanceOfClass(thiz, mBBCls)) {
                thiz.setFocusable(false);
                thiz.setFocusableInTouchMode(false);
            } else if (isInstanceOfClass(thiz, mInterstitialsCls)) {
                ((ViewGroup)thiz).setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                    @Override
                    public void onChildViewAdded(View parent, View child) {
                        if (DBG) {
                            Log.d(TAG, "OnHierarchyChangeListener onChildViewAdded parent:" + parent + " child:" + child);
                        }
                        if (child != null) {
                            child.setFocusable(false);
                            child.setFocusableInTouchMode(false);
                        }
                    }

                    @Override
                    public void onChildViewRemoved(View parent, View child) {
                        if (DBG) {
                            Log.d(TAG, "OnHierarchyChangeListener onChildViewRemoved parent:" + parent + " child:" + child);
                        }
                    }
                });
            }
        }
    }
    
    public int ViewSetViewFlagValues(int values, int mask) {
        if (DBG) {
            Log.d(TAG, "ViewSetViewFlagValues valuse:" + values + " mask:" + mask);
        }
        return values;
    }
    
    public boolean ViewSetOnClickListener(View thiz, View.OnClickListener l) {
        if (DBG) {
            Log.d(TAG, "ViewSetOnClickListener view:" + thiz + " listener:" + l);
        }
        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mBBCls) && thiz.isFocusable()) {
                thiz.setFocusable(false);
                return true;
            }
        }
        return false;
    }
    
    public void ViewPerformClickAddFocusables(View thiz, ArrayList<View> views, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClickAddFocusables view:" + thiz + " views:" + views + " direction:" + direction);
        }
    }
    
    public void ViewPerformClickAddFocusables(View thiz, ArrayList<View> views, int direction, int focusableMode, boolean canTakeFocus) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClickAddFocusables view:" + thiz 
                + " \nviews:" + views 
                + " \ndirection:" + direction 
                + " \nfocusableMode:" + focusableMode 
                + " \ncanTakeFocus:" + canTakeFocus);
        }
    }
    
    public boolean ViewPerformClick(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClick view:" + thiz);
        }
        return false;
    }
    
    public boolean ViewOnClick(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewOnClick view:" + thiz);
        }
        return false;
    }
    
    public boolean ViewOnPerformClick(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewOnPerformClick view:" + thiz);
        }
        return false;
    }
    
    public void ViewSetOnTouchListener(View thiz, View.OnTouchListener l) {
        if (DBG) {
            Log.d(TAG, "ViewSetOnTouchListener view:" + thiz + " listener:" + l);
        }
    }
    
    public void ViewRequestChildFocusPre(View thiz, ViewParent parent) {
        if (DBG) {
            Log.d(TAG, "ViewRequestChildFocusPre view:" + thiz + " parent:" + parent);
        }
    }
    
    public void ViewRequestChildFocusSuper(View thiz, ViewParent parent, View child, View focused) {
        /*if (DBG) {
            Log.d(TAG, "********************\nViewRequestChildFocusSuper view:" + thiz 
                + " \nparent:" + parent 
                + " \nchild:" + child 
                + " \nfocused:" + focused  
                + " \ninstanceof adapterview:" + (parent instanceof AdapterView)
                + " \ninstanceof ViewGroup:" + (parent instanceof ViewGroup)
                + "\n********************");
        }*/
    }

    public void ViewGroupRequestChildFocus(ViewParent parent, View child, View focused) {
        /*if (DBG) {
            Log.d(TAG, "ViewGroupRequestChildFocus parent:" + parent + " child:" + child + " focused:" + focused);
        }*/

        if (parent instanceof ViewRootImpl) {
            parent.requestChildFocus(child, focused);
        } else {
            ViewGroup viewGroup = (ViewGroup) parent;
            if (viewGroup.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) {
                return;
            }

            View groupFocused = viewGroup.getFocusedChild();
            
            //ViewUnFocus((View) viewGroup);
            viewGroup.clearFocusInternal(focused, false, false);

            if (groupFocused != child) {
                if (groupFocused != null) {
                    groupFocused.unFocus(focused);
                }

                //mFocused = child;
                ViewGroupSetFocused(viewGroup, child);
            }
            
            if (parent.getParent() != null) {
                //parent.getParent().requestChildFocus((View)parent, focused);
                ViewGroupRequestChildFocus(parent.getParent(), viewGroup, focused);
            }
        }
    }

    private void ViewGroupSetFocused(ViewGroup viewGroup, View child) {
        if (DBG) {
            Log.d(TAG, "ViewGroupSetFocused try to set child:" + child 
                + " as focused in ViewGroup:" + viewGroup 
                + " to replace old focused:" + viewGroup.getFocusedChild());
        }
        try {
            //Class cadCls = cad.getClass();
            Field field = ViewGroup.class.getDeclaredField("mFocused");
            field.setAccessible(true);
            field.set(viewGroup, child);
            field.setAccessible(false);
            //Log.d(TAG, "set mFocused:" + child + " groupFocused:" + viewGroup.getFocusedChild());
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    public void ViewOnFocusChanged(View thiz, boolean gainFocus, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewOnFocusChanged view:" + thiz + " gainFocus:" + gainFocus + " direction:" + direction);
        }

        if (mIsInNf && gainFocus && thiz.getParent() instanceof ViewGroup) {
            View item = EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView(thiz);
            if (item != null) {
                EpoxyRecyclerViewHelper.ensureFocusedItemVisible(item.getParent(), item);
            }
        }
    }
    
    public void ViewSetVisibility(View thiz, int visibility) {
        if (DBG) {
            Log.d(TAG, "ViewSetVisibility view:" + thiz + " visibility:" + visibility);
        }

        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mTagsTextCls) && thiz.isFocusable()) {
                thiz.setFocusable(false);
                thiz.setFocusableInTouchMode(false);
            }
        }
    }
    
    public boolean ViewSetFocusable(View thiz, boolean focusable) {
        if (DBG) {
            Log.d(TAG, "ViewSetFocusable view:" + thiz + " focusable:" + focusable);
        }

        if (mIsInNf) {
            if (thiz instanceof TextView || isInstanceOfClass(thiz, mBBCls)) {
                return focusable;
            }
        }
        return false;
    }
    
    public boolean ViewSetFocusableInTouchMode(View thiz, boolean focusableInTouchMode) {
        if (DBG) {
            Log.d(TAG, "ViewSetFocusableInTouchMode view:" + thiz + " focusableInTouchMode:" + focusableInTouchMode);
        }
        
        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mTagsTextCls) 
                || thiz instanceof TextView 
                || isInstanceOfClass(thiz, mBBCls)) {
                return focusableInTouchMode;
            }
        }
        return false;
    }
    
    public View ViewFocusSearch(View thiz, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewFocusSearch view:" + thiz + " direction:" + direction + " hasFocus:" + thiz.hasFocus());
        }

        if (mIsInNf) {
            if (thiz.hasFocus() 
                && direction == View.FOCUS_UP
                && EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView(thiz) != null 
                //search page
                && 1 == EpoxyRecyclerViewHelper.getItemPosition(thiz.getParent(), thiz)) {
                View first = EpoxyRecyclerViewHelper.getItemViewByPosition(thiz.getParent(), 0);
                if (first != null && !first.isFocusable()) {
                    if (DBG) {
                        Log.d(TAG, "found the second item in excyclerview!!!");
                    }
                    if (thiz.getParent() != null && thiz.getParent().getParent() != null) {
                        return thiz.getParent().getParent().focusSearch(thiz, direction);
                    }
                }
            }
        }
        return null;
    }
    
    public View ViewPerformClickFocusSearch(View thiz, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClickFocusSearch view:" + thiz + " direction:" + direction);
        }
        return null;
    }

    
    public View ViewGroupFocusSearch(ViewGroup thiz, View focused, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewGroupFocusSearch viewGroup:" + thiz + " focused:" + focused + " direction:" + direction);
        }
        return null;
    }

    
    public boolean ViewGroupAddFocusables(ViewGroup thiz, View child, ArrayList<View> views, int direction, int focusableMode) {
        if (DBG) {
            Log.d(TAG, "################\nViewGroupAddFocusables viewGroup:" + thiz 
                + " \nchild:" + child 
                + " \nviews size:" + views.size() 
                + " \ndirection:" + direction 
                + " \nfocusableMode:" + focusableMode 
                + "\n################");
        }
        return false;
    }

    public View FocusFinderFindSmallFocusView(ArrayList<View> focusables, View focused) {
        if (!mIsInTouchApp) {
            return null;
        }
        
        Rect tmpRect = null;
        if (focused != null) {
            tmpRect = new Rect();
            focused.getFocusedRect(tmpRect);
        }
        if (tmpRect != null) {
            DisplayMetrics metrice = focused.getContext().getResources().getDisplayMetrics();
            if (metrice.widthPixels == tmpRect.width() 
                && metrice.heightPixels == tmpRect.height()) {
                if (focusables != null && focusables.size() > 0) {
                    return focusables.get(0);
                }
            }
        }

        return null;
    }

    
    public ViewGroup FocusFinderFindNextFocus(FocusFinder thiz, ViewGroup root, View focused, Rect focusedRect, int direction) {
        if (DBG) {
            Log.d(TAG, "FocusFinderFindNextFocus FocusFinder:" + thiz 
                + " \nroot:" + root 
                + " \nfocused:" + focused 
                + " \nfocusedRect:" + focusedRect 
                + " \ndirection:" + direction);
        }

        /*if (isInNf() && root != null) {
            ViewParent parent = root.getParent();
            if (parent != null) {
                while (parent.getParent() != null && !(parent.getParent() instanceof ViewRootImpl)) {
                    parent = parent.getParent();
                }

                Log.d(TAG, "FocusFinderFindNextFocus get finally root:" + parent);
                return (ViewGroup) parent;
            }
        }*/
        return null;
    }
    
    public boolean FocusFinderBeamBeats(FocusFinder thiz, int direction, Rect source, Rect rect1, Rect rect2) {
        if (DBG) {
            Log.d(TAG, "FocusFinderBeamBeats FocusFinder:" + thiz 
                + " \ndirection:" + direction 
                + " \nsource:" + source 
                + " \nrect1:" + rect1 
                + " \nrect2:" + rect2);
        }
        return false;
    }
    
    public boolean FocusFinderIsCaredCandidate(FocusFinder thiz, Rect srcRect, Rect destRect, int direction) {
        if (DBG) {
            Log.d(TAG, "FocusFinderIsCaredCandidate FocusFinder:" + thiz + " srcRect:" + srcRect + " destRect:" + destRect + " direction:" + direction);
        }
        return false;
    }
    
    public boolean FocusFinderIsCandidate(FocusFinder thiz, Rect srcRect, Rect destRect, int direction) {
        return false;
    }
    
    public int ViewRootImplPerformFocusNavigation(KeyEvent event, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewRootImplPerformFocusNavigation event:" + event + " direction:" + direction);
        }
        return direction;
    }

    public void ViewRootImplOnPerformFocusNavigation(KeyEvent event, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewRootImplOnPerformFocusNavigation event:" + event + " direction:" + direction);
        }
    }

    public boolean ViewRootImplProcessKeyEvent(View view, KeyEvent event) {
        if (DBG) {
            Log.d(TAG, "ViewRootImplProcessKeyEvent event:" + event + " mView:" + view + " isInTouchApp:" + mIsInTouchApp);
        }

        if (mIsInTouchApp && view != null) {
            View focused = view.findFocus();
            if (DBG) {
                Log.d(TAG, "ViewRootImplProcessKeyEvent focused:" + focused); 
            }
            if (focused != null 
                && event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_DPAD_CENTER:
                        if (mIsInNf && focused instanceof AdapterView) {
                            AdapterView adapterView = (AdapterView) focused;
                            if (DBG) {
                                Log.d(TAG, "get adapter view:" + adapterView 
                                + " \nlistener:" + adapterView.getOnItemClickListener() 
                                + " \nselected view:" + adapterView.getSelectedView() 
                                + " \nselected item:" + adapterView.getSelectedItem() 
                                + " \nselected pos:" + adapterView.getSelectedItemPosition());
                            }
                            View selectedView = adapterView.getSelectedView();
                            if (adapterView.getOnItemClickListener() != null) {
                                if (DBG) {
                                    Log.d(TAG, "ViewRootImplProcessKeyEvent try to performItemClick adapterview:" + adapterView);
                                }
                                adapterView.performItemClick(selectedView, 
                                adapterView.getSelectedItemPosition(), 
                                adapterView.getSelectedItemId());
                                return true;
                            } else if (selectedView != null && getOnClickListenerV14(selectedView) != null) {
                                if (DBG) {
                                    Log.d(TAG, "ViewRootImplProcessKeyEvent try to performClick on selected view!");
                                }
                                selectedView.performClick();
                                return true;
                            }
                        }
                        break;
                    case KeyEvent.KEYCODE_BACK:
                        if (mIsInNf) {
                            View f = EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView(focused);
                            if ( f != null) {
                                View v = findChildBySimpleName((ViewGroup) focused.getRootView(), "BottomTabView");
                                if (v != null) {                                
                                    v.requestFocus();
                                    return true;
                                }
                            }
                        }
                        break;
                }
                
            }
        }

        if (DBG) {
            Log.d(TAG, "ViewRootImplProcessKeyEvent do nothing!");
        }
        return false;
    }

    private View findChildBySimpleName(ViewGroup parent, String simpleName) {
        if (parent == null || simpleName == null) {
            return null;
        }
        
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            
            // 判断子视图的类名是否匹配
            if (child.getClass().getSimpleName().equals(simpleName)) {
                return child; // 找到目标视图
            }
            
            // 如果子视图是 ViewGroup,递归查找
            if (child instanceof ViewGroup) {
                View result = findChildBySimpleName((ViewGroup) child, simpleName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null; // 未找到目标视图
    }

    private View.OnClickListener getOnClickListenerV14(View view) {
        View.OnClickListener retrievedListener = null;
        String viewStr = "android.view.View";
        String lInfoStr = "android.view.View$ListenerInfo";

        try {
            Field listenerField = Class.forName(viewStr).getDeclaredField("mListenerInfo");
            Object listenerInfo = null;

            if (listenerField != null) {
                listenerField.setAccessible(true);
                listenerInfo = listenerField.get(view);
            }

            Field clickListenerField = Class.forName(lInfoStr).getDeclaredField("mOnClickListener");

            if (clickListenerField != null && listenerInfo != null) {
                retrievedListener = (View.OnClickListener) clickListenerField.get(listenerInfo);
            }
        } catch (NoSuchFieldException ex) {
            Log.e("Reflection", "No Such Field.");
        } catch (IllegalAccessException ex) {
            Log.e("Reflection", "Illegal Access.");
        } catch (ClassNotFoundException ex) {
            Log.e("Reflection", "Class Not Found.");
        }

        return retrievedListener;
    }

    
    public void AdapterViewSetOnItemClickListener(AdapterView thiz, AdapterView.OnItemClickListener listener) {
        if (DBG) {
            Log.d(TAG, "AdapterViewSetOnItemClickListener AdapterView:" + thiz + " listener:" + listener);
        }
    }
    
    public boolean AdapterViewOnItemClick(AdapterView thiz, View view, int position, long id) {
        if (DBG) {
            Log.d(TAG, "AdapterViewOnItemClick AdapterView:" + thiz 
            + " \nview:" + view 
            + " \npos:" + position 
            + " \nid:" + id);
        }
        return false;
    }
    
    public boolean AdapterViewPerformItemClick(AdapterView thiz, View view, int position, long id) {
        if (DBG) {
            Log.d(TAG, "AdapterViewPerformItemClick AdapterView:" + thiz 
                + " \nview:" + view 
                + " \npos:" + position 
                + " \nid:" + id);
        }
        return false;
    }
    
    public void AdapterViewSetSelectedPositionInt(AdapterView thiz, int position) {
        if (DBG) {
            Log.d(TAG, "AdapterViewSetSelectedPositionInt AdapterView:" + thiz + " pos:" + position);
        }
    }
    
    public boolean ListViewAddHeaderView(ListView thiz, View v) {
        if (DBG) {
            Log.d(TAG, "ListViewAddHeaderView ListView:" + thiz + " v:" + v);
        }
        return false;
    }

    private static final class EpoxyRecyclerViewHelper {
    
        private static final int NO_POSITION = -1;

        public static void ensureFocusedItemVisible(Object epoxyRecyclerView, View focusedItem) {
            ensureFocusedItemVisible(epoxyRecyclerView, focusedItem, true);
        }
    
        /**
         * 检查 focusedItem 的可见性,并在不可见或部分可见时滚动到它的位置。
         *
         * @param epoxyRecyclerView EpoxyRecyclerView 实例(通过反射获取的)
         * @param focusedItem 当前聚焦的 View 对象
         */
        public static void ensureFocusedItemVisible(Object epoxyRecyclerView, View focusedItem, boolean recursive) {
            try {
                // 获取 LayoutManager
                Method getLayoutManagerMethod = epoxyRecyclerView.getClass().getMethod("getLayoutManager");
                Object layoutManager = getLayoutManagerMethod.invoke(epoxyRecyclerView);
    
                if (layoutManager == null || focusedItem == null) {
                    return; 
                }
    
                // 获取 focusedItem 的位置
                Method getChildAdapterPositionMethod = epoxyRecyclerView.getClass().getMethod("getChildAdapterPosition", View.class);
                int position = (int) getChildAdapterPositionMethod.invoke(epoxyRecyclerView, focusedItem);

                if (DBG) {
                    Log.d(TAG, "getChildAdapterPositionMethod:" + getChildAdapterPositionMethod + " positon:" + position);
                }
    
                if (position == NO_POSITION) {
                    return;
                }
    
                // 判断是否需要滚动到 focusedItem
                if (!isVisibleInLayoutManager(layoutManager, position) 
                    || !isItemFullyVisible(epoxyRecyclerView, focusedItem)) {
                    if (DBG) {
                        Log.d(TAG, "need to scroll to position:" + position);
                    }
                    scrollToPosition(epoxyRecyclerView, position);
                } 

                if (recursive) {
                    View view = EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView((View) epoxyRecyclerView);
                    if (DBG) {
                        Log.d(TAG, "find second recyclerview:" + view);
                    }
                    if (view != null) {
                        ensureFocusedItemVisible(view.getParent(), view, false);
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("EpoxyRecyclerViewHelper", "Error ensuring visibility: " + e.getMessage());
            }
        }
    
        /**
         * 判断 focusedItem 是否完全可见
         */
        private static boolean isItemFullyVisible(Object epoxyRecyclerView, View focusedItem) {
            try {
                // 获取子项的边界
                int itemTop = focusedItem.getTop();
                int itemBottom = focusedItem.getBottom();
                int itemLeft = focusedItem.getLeft();
                int itemRight = focusedItem.getRight();

                // 获取 RecyclerView 的可视区域
                View recyclerView = (View) epoxyRecyclerView;
                int recyclerTop = recyclerView.getPaddingTop();
                int recyclerBottom = recyclerView.getHeight() - recyclerView.getPaddingBottom();
                int recyclerLeft = recyclerView.getPaddingLeft();
                int recyclerRight = recyclerView.getWidth() - recyclerView.getPaddingRight();

                // 判断是否完全可见
                boolean isVerticallyVisible = itemTop >= recyclerTop && itemBottom <= recyclerBottom;
                boolean isHorizontallyVisible = itemLeft >= recyclerLeft && itemRight <= recyclerRight;

                if (DBG) {
                    Log.d(TAG, "isItemFullyVisible isVerticallyVisible:" + isVerticallyVisible + " isHorizontallyVisible:" + isHorizontallyVisible);
                }

                return isVerticallyVisible && isHorizontallyVisible;    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
            
        }
    
        /**
         * 滚动到指定位置
         */
        private static void scrollToPosition(Object epoxyRecyclerView, int position) {
            try {
                // 获取 smoothScrollToPosition 方法
                Method smoothScrollToPositionMethod = epoxyRecyclerView.getClass().getMethod("smoothScrollToPosition", int.class);
                smoothScrollToPositionMethod.invoke(epoxyRecyclerView, position);
    
            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("EpoxyRecyclerViewHelper", "Error scrolling to position: " + e.getMessage());
            }
        }

        /**
         * 检查 LayoutManager 中的可见性 (使用反射实现)
         */
        private static boolean isVisibleInLayoutManager(Object layoutManager, int position) {
            try {
                // 通过反射调用 findFirstVisibleItemPosition 和 findLastVisibleItemPosition 方法
                Method findFirstVisibleItemPositionMethod = layoutManager.getClass().getMethod("findFirstVisibleItemPosition");
                Method findLastVisibleItemPositionMethod = layoutManager.getClass().getMethod("findLastVisibleItemPosition");

                int firstVisibleItemPosition = (int) findFirstVisibleItemPositionMethod.invoke(layoutManager);
                int lastVisibleItemPosition = (int) findLastVisibleItemPositionMethod.invoke(layoutManager);

                if (DBG) {
                    Log.d(TAG, "isVisibleInGridLayoutManager first:" + (position >= firstVisibleItemPosition) 
                        + " last:" + (position <= lastVisibleItemPosition));
                }

                // 判断位置是否在可见范围内
                return position >= firstVisibleItemPosition && position <= lastVisibleItemPosition;

            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("EpoxyRecyclerViewHelper", "Error checking GridLayoutManager visibility: " + e.getMessage());
            }
            return false;
        }

处理投屏及个人资料头像点击对话框焦点停留问题

FocusFinder.java

 private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
        //Log.d(TAG,Log.getStackTraceString(new Throwable()));
        if (JoyarHelper.DBG) {
            Log.d(TAG, "findNextFocus root:" + root + " focused:" + focused);
        }
        View next = null;
        ViewGroup other = JoyarHelper.getInstance().FocusFinderGetRoot(this, focused);
        ViewGroup effectiveRoot = getEffectiveRoot(other != null ? other : root, focused);

        ViewGroup rv = JoyarHelper.getInstance().FocusFinderFindNextFocus(this, other != null ? other : root, focused, focusedRect, direction);
        if (rv != null) {
            effectiveRoot = rv;
        }
        if (focused != null) {
            next = findNextUserSpecifiedFocus(effectiveRoot, focused, direction);
        }
        if (next != null) {
            return next;
        }
        ArrayList<View> focusables = mTempList;

JoyarHelper.java

public class JoyarHelper {
    private final static String TAG = "JoyarHelper";
    public final static boolean DBG = SystemProperties.getBoolean("persist.joyar.debug", false);
    public final static JoyarHelper mInstance = new JoyarHelper();

    private static final int SHIFT_KEY = 3;

    private static final int DRAW_CORNERS_SIZE_DIP = 4;
    private static final int DRAW_STROKE_WIDTH_SIZE_DIP = 3;

    private final static String PACKAGE_NF = "frp.qhwiola.phgldfolhqw";
    private final static String PACKAGE_DP = "frp.glvqhb.glvqhbsoxv";
    private final static String PACKAGE_PV = "frp.dpdcrq.dyrg.wklugsduwbfolhqw";

    private Paint sDebugPaint;

    private boolean mIsInNf;
    private boolean mIsInDp;
    private boolean mIsInPv;
    private boolean mIsInTouchApp;
    private int mActivityCount;

    private static String mTagsTextCls;
    private static String mBBCls;
    private static String mInterstitialsCls;
    private static String mNfImgVCls;
    private static String mNfActivity;
    private static String mUiwebActivity;
    private static String mHActivity;

    static {
        mBBCls = decode("ElooerdugYlhz");
        mTagsTextCls = decode("QhwiolaWdjvWhawYlhz");
        mInterstitialsCls = decode("QhwiolaDfwlrqEduLqwhuvwlwldov");
        mNfImgVCls = decode("QhwiolaLpdjhYlhz");
        mNfActivity = decode("QhwiolaDfwlylwb");
        mUiwebActivity = decode("XLZheYlhzDfwlylwb");
        mHActivity = decode("KrphDfwlylwb");
    }

    protected void JoyarHelper() {
    }

    public static JoyarHelper getInstance() {
        return mInstance;
    }

    private final int dipsToPixels(View v, int dips) {
        float scale = v.getContext().getResources().getDisplayMetrics().density;
        return (int) (dips * scale + 0.5f);
    }

    public String encode(String input) {
        StringBuilder encoded = new StringBuilder();
        for (char c : input.toCharArray()) {
            if (Character.isLetter(c)) {
                char shift = (char) (c + SHIFT_KEY);
                if (Character.isLowerCase(c) && shift > 'z' || Character.isUpperCase(c) && shift > 'Z') {
                    shift -= 26;
                }
                encoded.append(shift);
            } else {
                encoded.append(c);
            }
        }
        return encoded.toString();
    }

    // Decryption method
    public static String decode(String input) {
        StringBuilder decoded = new StringBuilder();
        for (char c : input.toCharArray()) {
            if (Character.isLetter(c)) {
                char shift = (char) (c - SHIFT_KEY);
                if (Character.isLowerCase(c) && shift < 'a' || Character.isUpperCase(c) && shift < 'A') {
                    shift += 26;
                }
                decoded.append(shift);
            } else {
                decoded.append(c);
            }
        }
        return decoded.toString();
    }

    public void attachBaseContext(Context base) {
        if (DBG) {
            Log.d(TAG, "attachBaseContext pkg:" + base.getPackageName() + " base:" + base);
        }

        mActivityCount = 0;
        initTouchStatus(base.getPackageName());
    }

    private void initTouchStatus(final String packageName) {
        String encodeStr = encode(packageName);
        boolean ttr = isSupportTTRC();
        switch(encodeStr) {
            case PACKAGE_NF:
                if (DBG) {
                    Log.d(TAG, "attachBaseContext NF");
                }
                mIsInNf = true && ttr;
                mIsInTouchApp = true && ttr;
                break;
            case PACKAGE_DP:
                if (DBG) {
                    Log.d(TAG, "attachBaseContext DP");
                }
                mIsInDp = true && ttr;
                mIsInTouchApp = true && ttr;
                break;
            /*case PACKAGE_PV:
                if (DBG) Log.d(TAG, "attachBaseContext PV");
                mIsInPv = true && ttr;
                mIsInTouchApp = true && ttr;
                break;*/
            default:
                clearStatus();
                break;
        }

        //Log.d(TAG, "initTouchSatus NF:" + mIsInNf + " DP:" + mIsInDp + " PV:" + mIsInPv + " Touch:" + mIsInTouchApp);
    }

    private void clearStatus(   ) {
        mIsInDp = false;
        mIsInNf = false;
        mIsInPv = false;
        mIsInTouchApp = false;
        mActivityCount = 0;
    }

    private boolean isSupportTTRC() {
        return SvtGeneralProperties.getBoolProperty("CONFIG_SUPPORT_TOUCH_TTRC");
    }

    public boolean isInNf() {
        return mIsInNf && isSupportTTRC();
    }

    public void setInNfMode(boolean isNf) {
        mIsInNf = isNf  && isSupportTTRC();
        mIsInTouchApp = isNf && isSupportTTRC();
    }

    public boolean isInDf() {
        return mIsInDp && isSupportTTRC();
    }

    public void setInDpMode(boolean isDp) {
        mIsInDp = isDp && isSupportTTRC();
        mIsInTouchApp = isDp && isSupportTTRC();
    }

    public boolean isInPv() {
        return mIsInPv && isSupportTTRC();
    }

    public void setInPvMode(boolean isPv) {
        mIsInPv = isPv && isSupportTTRC();
        mIsInTouchApp = isPv && isSupportTTRC();
    }

    public boolean isInTouchApp() {
        return mIsInTouchApp && isSupportTTRC();
    }

    public void onActivityStarted(Activity activity) {
        initTouchStatus(activity.getPackageName());
        if (mIsInTouchApp) {
            ++mActivityCount;
        }
    }

    public void onActivityStopped(Activity activity) {
        if (mIsInTouchApp) {
            --mActivityCount;
            if (mActivityCount <= 0) {
                clearStatus();
            }
        }
    }

    public void setInTouchAppMode(boolean isTouch) {
        mIsInTouchApp = isTouch && isSupportTTRC();
    }
    
    private Paint getDebugPaint() {
        if (sDebugPaint == null) {
            sDebugPaint = new Paint();
            sDebugPaint.setAntiAlias(SystemProperties.getBoolean("persist.joyar.antialias", false));
        }
        return sDebugPaint;
    }

    public boolean ViewIsFullscreenView(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewIsFullscreenView view:" + thiz);
        }
        if (mIsInNf) {
            DisplayMetrics metrice = thiz.getContext().getResources().getDisplayMetrics();
            Rect tmpRect = new Rect();
            thiz.getFocusedRect(tmpRect);
            if (metrice.widthPixels == tmpRect.width() 
                && metrice.heightPixels == tmpRect.height()) {
                if (DBG) {
                    Log.d(TAG, "cause a match full screen view, sould skip it?");
                }
                return true;
            } /*else if ((tmpRect.width() == 0 || tmpRect.height() == 0) 
                && !isInstanceOfClass(thiz, mNfImgVCls) 
                && !isInstanceOfClass(thiz.getContext(), mNfActivity)) {
                if (DBG) {
                    Log.d(TAG, "cause width or height is 0, sould skip it?");
                }
                return true;
            }*/
        }
        return false;
    }

    public void ViewOnDraw(View thiz, Canvas canvas, Rect rect) {
        if (DBG) {
            Log.d(TAG, "ViewOnDraw view:" + thiz + " canvas:" + canvas);
        }

        //Log.d(TAG, "ViewOnDraw isInTouchApp:" + mIsInTouchApp + " isFocused:" + thiz.isFocused() + " rect:" + rect);
        if (mIsInTouchApp && thiz.isFocused()) {
            final int cornerSquareSize = dipsToPixels(thiz, DRAW_CORNERS_SIZE_DIP);
            final int strokeWidthSize = dipsToPixels(thiz, DRAW_STROKE_WIDTH_SIZE_DIP);
            Rect focusedRect = new Rect();
            if (thiz instanceof EditText && rect != null) {
                focusedRect = rect;
            } else if (thiz instanceof AdapterView) {
                View selected = ((AdapterView)thiz).getSelectedView();
                if (DBG) {
                    Log.d(TAG, "get a adapter view:" + thiz + " selected view:" + selected);
                }
                if (selected != null) {
                    selected.getDrawingRect(focusedRect);
                    ((AdapterView)thiz).offsetDescendantRectToMyCoords(selected, focusedRect);
                    if (DBG) {
                        Log.d(TAG, "get selected view rect:" + focusedRect);
                    }
                }
            } else {
                if (mIsInDp) {
                    thiz.getFocusedRect(focusedRect);
                } else {
                    thiz.getDrawingRect(focusedRect);
                }
            }

            boolean isBigger = isInstanceOfClass(thiz, mNfImgVCls) || isInstanceOfClass(thiz, "PlayLoadingReplayButton");
            int strokeWidth = JoyarHelper.DBG 
                ? SystemProperties.getInt("persist.joyar.stroke", DRAW_STROKE_WIDTH_SIZE_DIP) 
                : DRAW_STROKE_WIDTH_SIZE_DIP;

            Paint paint = getDebugPaint();
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(dipsToPixels(thiz, 
                isBigger ? strokeWidth * 3 : strokeWidth));

            Shader linearGradient = new LinearGradient(
                    focusedRect.left, focusedRect.top, // 渐变起点
                    focusedRect.right, focusedRect.bottom, // 渐变终点
                    Color.RED, Color.BLUE, // 渐变颜色
                    Shader.TileMode.CLAMP // 边缘模式
            );

            paint.setShader(linearGradient);

            canvas.drawRect(focusedRect, paint);
        }
    }

    private boolean isInstanceOfClass(Object view, String name) {
        if (view == null || name == null) {
            return false;
        }
        
        Class<?> cls = view.getClass();
        
        for (; cls != Object.class; cls = cls.getSuperclass()) {
            if (name.equals(cls.getSimpleName())) {
                if (DBG) {
                    Log.d(TAG, "############found isInstanceOfClass class:" + cls + " ############");
                }
                return true;
            }
        }
        return false;
    }

    
    public void ViewAddPerformClickViews(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewAddPerformClickViews view:" + thiz + " Context:" + thiz.getContext());
        }

        if (mIsInNf && thiz.getContext() != null) {
            String clsName = thiz.getContext().getClass().getSimpleName();
            if (mUiwebActivity.equals(clsName)) {
                if (thiz instanceof VideoView) {
                    thiz.setFocusable(false);
                    thiz.setFocusableInTouchMode(false);
                }
            } else if (mHActivity.equals(clsName)) {
                if (isInstanceOfClass(thiz, mTagsTextCls) || thiz instanceof TextView) {
                    thiz.setFocusable(false);
                    thiz.setFocusableInTouchMode(false);
                } else if (isInstanceOfClass(thiz, mBBCls)) {
                    thiz.setFocusable(false);
                    thiz.setFocusableInTouchMode(false);
                } else if (isInstanceOfClass(thiz, mInterstitialsCls)) {
                    ((ViewGroup)thiz).setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                        @Override
                        public void onChildViewAdded(View parent, View child) {
                            if (DBG) {
                                Log.d(TAG, "OnHierarchyChangeListener onChildViewAdded parent:" + parent + " child:" + child);
                            }
                            if (child != null) {
                                child.setFocusable(false);
                                child.setFocusableInTouchMode(false);
                            }
                        }

                        @Override
                        public void onChildViewRemoved(View parent, View child) {
                            if (DBG) {
                                Log.d(TAG, "OnHierarchyChangeListener onChildViewRemoved parent:" + parent + " child:" + child);
                            }
                        }
                    });
                }
            }

            if (isMdxRecyclerView(thiz)) {
                ((ViewGroup)thiz).setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                    @Override
                    public void onChildViewAdded(View parent, View child) {
                        if (DBG) {
                            Log.d(TAG, "OnHierarchyChangeListener onChildViewAdded parent:" + parent + " child:" + child);
                        }
                        View view = EpoxyRecyclerViewHelper.getItemViewByPosition(parent, 1);
                        if (view != null) {
                            view.requestFocus();
                        } else {
                            parent.requestFocus();
                        }
                    }

                    @Override
                    public void onChildViewRemoved(View parent, View child) {
                        if (DBG) {
                            Log.d(TAG, "OnHierarchyChangeListener onChildViewRemoved parent:" + parent + " child:" + child);
                        }
                    }
                });
            }
        }
    }
    
    public int ViewSetViewFlagValues(int values, int mask) {
        if (DBG) {
            Log.d(TAG, "ViewSetViewFlagValues valuse:" + values + " mask:" + mask);
        }
        return values;
    }
    
    public boolean ViewSetOnClickListener(View thiz, View.OnClickListener l) {
        if (DBG) {
            Log.d(TAG, "ViewSetOnClickListener view:" + thiz + " listener:" + l);
        }
        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mBBCls) && thiz.isFocusable()) {
                thiz.setFocusable(false);
                return true;
            }
        }
        return false;
    }
    
    public void ViewPerformClickAddFocusables(View thiz, ArrayList<View> views, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClickAddFocusables view:" + thiz + " views:" + views + " direction:" + direction);
        }
    }
    
    public void ViewPerformClickAddFocusables(View thiz, ArrayList<View> views, int direction, int focusableMode, boolean canTakeFocus) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClickAddFocusables view:" + thiz 
                + " \nviews:" + views 
                + " \ndirection:" + direction 
                + " \nfocusableMode:" + focusableMode 
                + " \ncanTakeFocus:" + canTakeFocus);
        }
    }
    
    public boolean ViewPerformClick(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClick view:" + thiz);
        }
        return false;
    }
    
    public boolean ViewOnClick(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewOnClick view:" + thiz);
        }
        return false;
    }
    
    public boolean ViewOnPerformClick(View thiz) {
        if (DBG) {
            Log.d(TAG, "ViewOnPerformClick view:" + thiz);
        }
        return false;
    }
    
    public void ViewSetOnTouchListener(View thiz, View.OnTouchListener l) {
        if (DBG) {
            Log.d(TAG, "ViewSetOnTouchListener view:" + thiz + " listener:" + l);
        }
    }
    
    public void ViewRequestChildFocusPre(View thiz, ViewParent parent) {
        if (DBG) {
            Log.d(TAG, "ViewRequestChildFocusPre view:" + thiz + " parent:" + parent);
        }
    }
    
    public void ViewRequestChildFocusSuper(View thiz, ViewParent parent, View child, View focused) {
        /*if (DBG) {
            Log.d(TAG, "********************\nViewRequestChildFocusSuper view:" + thiz 
                + " \nparent:" + parent 
                + " \nchild:" + child 
                + " \nfocused:" + focused  
                + " \ninstanceof adapterview:" + (parent instanceof AdapterView)
                + " \ninstanceof ViewGroup:" + (parent instanceof ViewGroup)
                + "\n********************");
        }*/
    }

    public void ViewGroupRequestChildFocus(ViewParent parent, View child, View focused) {
        /*if (DBG) {
            Log.d(TAG, "ViewGroupRequestChildFocus parent:" + parent + " child:" + child + " focused:" + focused);
        }*/

        if (parent instanceof ViewRootImpl) {
            parent.requestChildFocus(child, focused);
        } else {
            ViewGroup viewGroup = (ViewGroup) parent;
            if (viewGroup.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) {
                return;
            }

            View groupFocused = viewGroup.getFocusedChild();
            
            //ViewUnFocus((View) viewGroup);
            viewGroup.clearFocusInternal(focused, false, false);

            if (groupFocused != child) {
                if (groupFocused != null) {
                    groupFocused.unFocus(focused);
                }

                //mFocused = child;
                ViewGroupSetFocused(viewGroup, child);
            }
            
            if (parent.getParent() != null) {
                //parent.getParent().requestChildFocus((View)parent, focused);
                ViewGroupRequestChildFocus(parent.getParent(), viewGroup, focused);
            }
        }
    }

    private void ViewGroupSetFocused(ViewGroup viewGroup, View child) {
        if (DBG) {
            Log.d(TAG, "ViewGroupSetFocused try to set child:" + child 
                + " as focused in ViewGroup:" + viewGroup 
                + " to replace old focused:" + viewGroup.getFocusedChild());
        }
        try {
            //Class cadCls = cad.getClass();
            Field field = ViewGroup.class.getDeclaredField("mFocused");
            field.setAccessible(true);
            field.set(viewGroup, child);
            field.setAccessible(false);
            //Log.d(TAG, "set mFocused:" + child + " groupFocused:" + viewGroup.getFocusedChild());
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    public void ViewOnFocusChanged(View thiz, boolean gainFocus, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewOnFocusChanged view:" + thiz + " gainFocus:" + gainFocus + " direction:" + direction);
        }

        if (mIsInNf && gainFocus && thiz.getParent() instanceof ViewGroup) {
            View item = EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView(thiz);
            if (item != null) {
                EpoxyRecyclerViewHelper.ensureFocusedItemVisible(item.getParent(), item);
            }
        }
    }
    
    public void ViewSetVisibility(View thiz, int visibility) {
        if (DBG) {
            Log.d(TAG, "ViewSetVisibility view:" + thiz + " visibility:" + visibility);
        }

        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mTagsTextCls) && thiz.isFocusable()) {
                thiz.setFocusable(false);
                thiz.setFocusableInTouchMode(false);
            }
        }
    }
    
    public boolean ViewSetFocusable(View thiz, boolean focusable) {
        if (DBG) {
            Log.d(TAG, "ViewSetFocusable view:" + thiz + " focusable:" + focusable);
        }

        if (mIsInNf) {
            if (thiz instanceof TextView 
                || thiz instanceof VideoView 
                || thiz instanceof ScrollView
                || isInstanceOfClass(thiz, mBBCls)) {
                return focusable;
            }
        }
        return false;
    }

    public View getFullscreenDialogDecorView(View focused) {
        if (focused == null) {
            return null;
        }

        View child0 = ((ViewGroup)focused.getRootView()).getChildAt(0);

        if (DBG) {
            Log.d(TAG, "getFullscreenDialogDecorView child0:" + child0 
                + " focused context:" + focused.getContext() 
                + " child 0 context:" + (child0 == null ? null : child0.getContext()));
        }
        
        Object frag = findFullScreenDialogByTag(child0 != null ? child0.getContext() : focused.getContext());
        if (DBG) {
            Log.d(TAG, "getFullscreenDialogDecorView found frag:" + frag);
        }
        if (frag != null && isFragmentAdded(frag)) {
            try {
                Method getViewMethod = frag.getClass().getMethod("getView");
                View view = (View) getViewMethod.invoke(frag);
                if (DBG) {
                    Log.d(TAG, "found a  DialogFragment view:" + view);
                }

                return view;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public View getDialogFragmentView(Object frag) {
        try {
            Method getViewMethod = frag.getClass().getMethod("getView");
            View view = (View) getViewMethod.invoke(frag);
            if (DBG) {
                Log.d(TAG, "found a  DialogFragment view:" + view);
            }
            return view;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object findFragmentByTag(Object context, String tag) {
        if (DBG) {
            Log.d(TAG, "findFragmentByTag context:" + context + " app activity:" + isInstanceOfClass(context, "AppCompatActivity"));
        }
        if (context == null || !isInstanceOfClass(context, "AppCompatActivity")) {
            return null;
        }
        try {
            // 获取 Activity 的 getSupportFragmentManager() 方法
            Method getFragmentManagerMethod = context.getClass().getMethod("getSupportFragmentManager");
            // 调用该方法获取 FragmentManager
            Object fragmentManager = getFragmentManagerMethod.invoke(context);

            // 获取 FragmentManager 的 findFragmentByTag() 方法
            Method findFragmentByTagMethod = fragmentManager.getClass().getMethod("findFragmentByTag", String.class);
            return findFragmentByTagMethod.invoke(fragmentManager, tag);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }

    public boolean isFragmentAdded(Object frag) {
        if (frag == null) {
            return false;
        }
        
        try {
            Method fragIsAddedMethod = frag.getClass().getMethod("isAdded");
            boolean ret = (boolean)fragIsAddedMethod.invoke(frag);
            if (DBG) {
                Log.d(TAG, "isFragmentAdded:" + frag 
                    + " isAdded:" + ret);
            }
            return ret;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public Object findFullScreenDialogByTag(Object context    ) {
        return findFragmentByTag(context, "FullScreenDialogTag");
    }

    public boolean isCastSheetDialogFragShow(Object context) {
        Object frag = findFullScreenDialogByTag(context);
        return frag != null && isFragmentAdded(frag);
    }

    private boolean isMdxRecyclerView(View view) {
        if (DBG) Log.d(TAG, "isMdxRecyclerView context:" + view.getContext());
        return view == null ? false : 
            "RecyclerView".equals(view.getClass().getSimpleName()) 
            && isCastSheetDialogFragShow(view.getContext());
    }
    
    public boolean ViewSetFocusableInTouchMode(View thiz, boolean focusableInTouchMode) {
        if (DBG) {
            Log.d(TAG, "ViewSetFocusableInTouchMode view:" + thiz + " focusableInTouchMode:" + focusableInTouchMode);
        }
        
        if (mIsInNf) {
            if (isInstanceOfClass(thiz, mTagsTextCls) 
                || thiz instanceof TextView 
                || thiz instanceof VideoView
                || thiz instanceof ScrollView
                || isInstanceOfClass(thiz, mBBCls)) {
                return focusableInTouchMode;
            }
        }
        return false;
    }
    
    public View ViewFocusSearch(View thiz, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewFocusSearch view:" + thiz + " direction:" + direction + " hasFocus:" + thiz.hasFocus());
        }

        if (mIsInNf) {
            if (thiz.hasFocus() 
                && direction == View.FOCUS_UP
                && EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView(thiz) != null 
                //search page
                && 1 == EpoxyRecyclerViewHelper.getItemPosition(thiz.getParent(), thiz)) {
                View first = EpoxyRecyclerViewHelper.getItemViewByPosition(thiz.getParent(), 0);
                if (first != null && !first.isFocusable()) {
                    if (DBG) {
                        Log.d(TAG, "found the second item in excyclerview!!!");
                    }
                    if (thiz.getParent() != null && thiz.getParent().getParent() != null) {
                        return thiz.getParent().getParent().focusSearch(thiz, direction);
                    }
                }
            }
        }
        return null;
    }
    
    public View ViewPerformClickFocusSearch(View thiz, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewPerformClickFocusSearch view:" + thiz + " direction:" + direction);
        }
        return null;
    }

    
    public View ViewGroupFocusSearch(ViewGroup thiz, View focused, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewGroupFocusSearch viewGroup:" + thiz + " focused:" + focused + " direction:" + direction);
        }
        return null;
    }

    
    public boolean ViewGroupAddFocusables(ViewGroup thiz, View child, ArrayList<View> views, int direction, int focusableMode) {
        /*if (DBG) {
            Log.d(TAG, "################\nViewGroupAddFocusables viewGroup:" + thiz 
                + " \nchild:" + child 
                + " \nviews size:" + views.size() 
                + " \ndirection:" + direction 
                + " \nfocusableMode:" + focusableMode 
                + "\n################");
        }*/
        return false;
    }

    public View FocusFinderFindSmallFocusView(ArrayList<View> focusables, View focused) {
        if (!mIsInTouchApp) {
            return null;
        }
        
        Rect tmpRect = null;
        if (focused != null) {
            tmpRect = new Rect();
            focused.getFocusedRect(tmpRect);
        }
        if (tmpRect != null) {
            DisplayMetrics metrice = focused.getContext().getResources().getDisplayMetrics();
            if (DBG) {
                Log.d(TAG, "FocusFinderFindSmallFocusView focused:" + focused 
                    + " width:" + tmpRect.width() 
                    + " height:" + tmpRect.height() 
                    + " metrice:" + metrice);
            }
            if (metrice.widthPixels == tmpRect.width() 
                && metrice.heightPixels == tmpRect.height()) {
                if (focusables != null && focusables.size() > 0) {
                    return focusables.get(0);
                }
            }
        }
        

        return null;
    }

    public ViewGroup FocusFinderGetRoot(FocusFinder thiz, View focused) {
        if (DBG) {
            Log.d(TAG, "FocusFinderGetRoot FocusFinder:" + thiz + " focused:" + focused);
        }

        if (focused == null) {
            return null;
        }

        View view = getFullscreenDialogDecorView(focused);

        if (DBG) {
            Log.d(TAG, "FocusFinderGetRoot frag root:" + view);
        }

        return view != null ? (ViewGroup)view : null;
    }
    public ViewGroup FocusFinderFindNextFocus(FocusFinder thiz, ViewGroup root, View focused, Rect focusedRect, int direction) {
        if (DBG) {
            Log.d(TAG, "FocusFinderFindNextFocus FocusFinder:" + thiz 
                + " \nroot:" + root 
                + " \nfocused:" + focused 
                + " \nfocusedRect:" + focusedRect 
                + " \ndirection:" + direction);
        }
        return null;
    }
    
    public boolean FocusFinderBeamBeats(FocusFinder thiz, int direction, Rect source, Rect rect1, Rect rect2) {
        if (DBG) {
            Log.d(TAG, "FocusFinderBeamBeats FocusFinder:" + thiz 
                + " \ndirection:" + direction 
                + " \nsource:" + source 
                + " \nrect1:" + rect1 
                + " \nrect2:" + rect2);
        }
        return false;
    }
    
    public boolean FocusFinderIsCaredCandidate(FocusFinder thiz, Rect srcRect, Rect destRect, int direction) {
        if (DBG) {
            Log.d(TAG, "FocusFinderIsCaredCandidate FocusFinder:" + thiz + " srcRect:" + srcRect + " destRect:" + destRect + " direction:" + direction);
        }
        return false;
    }
    
    public boolean FocusFinderIsCandidate(FocusFinder thiz, Rect srcRect, Rect destRect, int direction) {
        return false;
    }
    
    public int ViewRootImplPerformFocusNavigation(KeyEvent event, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewRootImplPerformFocusNavigation event:" + event + " direction:" + direction);
        }
        return direction;
    }

    public void ViewRootImplOnPerformFocusNavigation(KeyEvent event, int direction) {
        if (DBG) {
            Log.d(TAG, "ViewRootImplOnPerformFocusNavigation event:" + event + " direction:" + direction);
        }
    }

    public boolean ViewRootImplProcessKeyEvent(View view, KeyEvent event) {
        if (DBG) {
            Log.d(TAG, "ViewRootImplProcessKeyEvent event:" + event + " mView:" + view + " isInTouchApp:" + mIsInTouchApp);
        }

        if (mIsInTouchApp && view != null) {
            View focused = view.findFocus();
            if (DBG) {
                Log.d(TAG, "ViewRootImplProcessKeyEvent focused:" + focused); 
            }
            if (focused != null 
                && event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_DPAD_CENTER:
                        if (mIsInNf && focused instanceof AdapterView) {
                            AdapterView adapterView = (AdapterView) focused;
                            if (DBG) {
                                Log.d(TAG, "get adapter view:" + adapterView 
                                + " \nlistener:" + adapterView.getOnItemClickListener() 
                                + " \nselected view:" + adapterView.getSelectedView() 
                                + " \nselected item:" + adapterView.getSelectedItem() 
                                + " \nselected pos:" + adapterView.getSelectedItemPosition());
                            }
                            View selectedView = adapterView.getSelectedView();
                            if (adapterView.getOnItemClickListener() != null) {
                                if (DBG) {
                                    Log.d(TAG, "ViewRootImplProcessKeyEvent try to performItemClick adapterview:" + adapterView);
                                }
                                adapterView.performItemClick(selectedView, 
                                adapterView.getSelectedItemPosition(), 
                                adapterView.getSelectedItemId());
                                return true;
                            } else if (selectedView != null && getOnClickListenerV14(selectedView) != null) {
                                if (DBG) {
                                    Log.d(TAG, "ViewRootImplProcessKeyEvent try to performClick on selected view!");
                                }
                                selectedView.performClick();
                                return true;
                            }
                        }
                        break;
                    case KeyEvent.KEYCODE_BACK:
                        if (mIsInNf) {
                            View f = EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView(focused);
                            if ( f != null) {
                                View v = findChildBySimpleName((ViewGroup) focused.getRootView(), "BottomTabView");
                                if (v != null) {                                
                                    v.requestFocus();
                                    return true;
                                }
                            }
                        }
                        break;
                }
                
            }
        }

        if (DBG) {
            Log.d(TAG, "ViewRootImplProcessKeyEvent do nothing!");
        }
        return false;
    }

    private View findChildBySimpleName(ViewGroup parent, String simpleName) {
        if (parent == null || simpleName == null) {
            return null;
        }
        
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            
            // 判断子视图的类名是否匹配
            if (child.getClass().getSimpleName().equals(simpleName)) {
                return child; // 找到目标视图
            }
            
            // 如果子视图是 ViewGroup,递归查找
            if (child instanceof ViewGroup) {
                View result = findChildBySimpleName((ViewGroup) child, simpleName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null; // 未找到目标视图
    }

    private View.OnClickListener getOnClickListenerV14(View view) {
        View.OnClickListener retrievedListener = null;
        String viewStr = "android.view.View";
        String lInfoStr = "android.view.View$ListenerInfo";

        try {
            Field listenerField = Class.forName(viewStr).getDeclaredField("mListenerInfo");
            Object listenerInfo = null;

            if (listenerField != null) {
                listenerField.setAccessible(true);
                listenerInfo = listenerField.get(view);
            }

            Field clickListenerField = Class.forName(lInfoStr).getDeclaredField("mOnClickListener");

            if (clickListenerField != null && listenerInfo != null) {
                retrievedListener = (View.OnClickListener) clickListenerField.get(listenerInfo);
            }
        } catch (NoSuchFieldException ex) {
            Log.e("Reflection", "No Such Field.");
        } catch (IllegalAccessException ex) {
            Log.e("Reflection", "Illegal Access.");
        } catch (ClassNotFoundException ex) {
            Log.e("Reflection", "Class Not Found.");
        }

        return retrievedListener;
    }

    
    public void AdapterViewSetOnItemClickListener(AdapterView thiz, AdapterView.OnItemClickListener listener) {
        if (DBG) {
            Log.d(TAG, "AdapterViewSetOnItemClickListener AdapterView:" + thiz + " listener:" + listener);
        }
    }
    
    public boolean AdapterViewOnItemClick(AdapterView thiz, View view, int position, long id) {
        if (DBG) {
            Log.d(TAG, "AdapterViewOnItemClick AdapterView:" + thiz 
            + " \nview:" + view 
            + " \npos:" + position 
            + " \nid:" + id);
        }
        return false;
    }
    
    public boolean AdapterViewPerformItemClick(AdapterView thiz, View view, int position, long id) {
        if (DBG) {
            Log.d(TAG, "AdapterViewPerformItemClick AdapterView:" + thiz 
                + " \nview:" + view 
                + " \npos:" + position 
                + " \nid:" + id);
        }
        return false;
    }
    
    public void AdapterViewSetSelectedPositionInt(AdapterView thiz, int position) {
        if (DBG) {
            Log.d(TAG, "AdapterViewSetSelectedPositionInt AdapterView:" + thiz + " pos:" + position);
        }
    }
    
    public boolean ListViewAddHeaderView(ListView thiz, View v) {
        if (DBG) {
            Log.d(TAG, "ListViewAddHeaderView ListView:" + thiz + " v:" + v);
        }
        return false;
    }

    private static final class EpoxyRecyclerViewHelper {
    
        private static final int NO_POSITION = -1;

        public static void ensureFocusedItemVisible(Object epoxyRecyclerView, View focusedItem) {
            ensureFocusedItemVisible(epoxyRecyclerView, focusedItem, true);
        }
    
        /**
         * 检查 focusedItem 的可见性,并在不可见或部分可见时滚动到它的位置。
         *
         * @param epoxyRecyclerView EpoxyRecyclerView 实例(通过反射获取的)
         * @param focusedItem 当前聚焦的 View 对象
         */
        public static void ensureFocusedItemVisible(Object epoxyRecyclerView, View focusedItem, boolean recursive) {
            try {
                // 获取 LayoutManager
                Method getLayoutManagerMethod = epoxyRecyclerView.getClass().getMethod("getLayoutManager");
                Object layoutManager = getLayoutManagerMethod.invoke(epoxyRecyclerView);
    
                if (layoutManager == null || focusedItem == null) {
                    return; 
                }
    
                // 获取 focusedItem 的位置
                Method getChildAdapterPositionMethod = epoxyRecyclerView.getClass().getMethod("getChildAdapterPosition", View.class);
                int position = (int) getChildAdapterPositionMethod.invoke(epoxyRecyclerView, focusedItem);

                if (DBG) {
                    Log.d(TAG, "getChildAdapterPositionMethod:" + getChildAdapterPositionMethod + " positon:" + position);
                }
    
                if (position == NO_POSITION) {
                    return;
                }
    
                // 判断是否需要滚动到 focusedItem
                if (!isVisibleInLayoutManager(layoutManager, position) 
                    || !isItemFullyVisible(epoxyRecyclerView, focusedItem)) {
                    if (DBG) {
                        Log.d(TAG, "need to scroll to position:" + position);
                    }
                    scrollToPosition(epoxyRecyclerView, position);
                } 

                if (recursive) {
                    View view = EpoxyRecyclerViewHelper.findParentEpoxyRecyclerView((View) epoxyRecyclerView);
                    if (DBG) {
                        Log.d(TAG, "find second recyclerview:" + view);
                    }
                    if (view != null) {
                        ensureFocusedItemVisible(view.getParent(), view, false);
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("EpoxyRecyclerViewHelper", "Error ensuring visibility: " + e.getMessage());
            }
        }
    
        /**
         * 判断 focusedItem 是否完全可见
         */
        private static boolean isItemFullyVisible(Object epoxyRecyclerView, View focusedItem) {
            try {
                // 获取子项的边界
                int itemTop = focusedItem.getTop();
                int itemBottom = focusedItem.getBottom();
                int itemLeft = focusedItem.getLeft();
                int itemRight = focusedItem.getRight();

                // 获取 RecyclerView 的可视区域
                View recyclerView = (View) epoxyRecyclerView;
                int recyclerTop = recyclerView.getPaddingTop();
                int recyclerBottom = recyclerView.getHeight() - recyclerView.getPaddingBottom();
                int recyclerLeft = recyclerView.getPaddingLeft();
                int recyclerRight = recyclerView.getWidth() - recyclerView.getPaddingRight();

                // 判断是否完全可见
                boolean isVerticallyVisible = itemTop >= recyclerTop && itemBottom <= recyclerBottom;
                boolean isHorizontallyVisible = itemLeft >= recyclerLeft && itemRight <= recyclerRight;

                if (DBG) {
                    Log.d(TAG, "isItemFullyVisible isVerticallyVisible:" + isVerticallyVisible + " isHorizontallyVisible:" + isHorizontallyVisible);
                }

                return isVerticallyVisible && isHorizontallyVisible;    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
            
        }
    
        /**
         * 滚动到指定位置
         */
        private static void scrollToPosition(Object epoxyRecyclerView, int position) {
            try {
                // 获取 smoothScrollToPosition 方法
                Method smoothScrollToPositionMethod = epoxyRecyclerView.getClass().getMethod("smoothScrollToPosition", int.class);
                smoothScrollToPositionMethod.invoke(epoxyRecyclerView, position);
    
            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("EpoxyRecyclerViewHelper", "Error scrolling to position: " + e.getMessage());
            }
        }

        /**
         * 检查 LayoutManager 中的可见性 (使用反射实现)
         */
        private static boolean isVisibleInLayoutManager(Object layoutManager, int position) {
            try {
                // 通过反射调用 findFirstVisibleItemPosition 和 findLastVisibleItemPosition 方法
                Method findFirstVisibleItemPositionMethod = layoutManager.getClass().getMethod("findFirstVisibleItemPosition");
                Method findLastVisibleItemPositionMethod = layoutManager.getClass().getMethod("findLastVisibleItemPosition");

                int firstVisibleItemPosition = (int) findFirstVisibleItemPositionMethod.invoke(layoutManager);
                int lastVisibleItemPosition = (int) findLastVisibleItemPositionMethod.invoke(layoutManager);

                if (DBG) {
                    Log.d(TAG, "isVisibleInGridLayoutManager first:" + (position >= firstVisibleItemPosition) 
                        + " last:" + (position <= lastVisibleItemPosition));
                }

                // 判断位置是否在可见范围内
                return position >= firstVisibleItemPosition && position <= lastVisibleItemPosition;

            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("EpoxyRecyclerViewHelper", "Error checking GridLayoutManager visibility: " + e.getMessage());
            }
            return false;
        }

        /**
         * 查找给定的 View 是否属于某个 EpoxyRecyclerView。
         *
         * @param view 待检查的 View
         * @return 如果 view 的 parent 是 EpoxyRecyclerView,则返回 view;否则返回 null
         */
        public static View findParentEpoxyRecyclerView(View view) {
            if (view == null) {
                return null;
            }

            // 从 view 开始,获取父视图
            ViewParent parent = view.getParent();

            //Log.d(TAG, "findParentEpoxyRecyclerView parent:" + parent);
            
            // 如果 view.getParent() 符合条件,直接返回 view
            if (parent != null && isInstanceOfClass(parent, "EpoxyRecyclerView")) {
                return view;
            }
        
            // 遍历父视图链,直到找到符合条件的 EpoxyRecyclerView
            while (parent != null) {
                //Log.d(TAG, "findParentEpoxyRecyclerView parent:" + parent);
                if (parent.getParent() != null && isInstanceOfClass(parent.getParent(), "EpoxyRecyclerView")) {
                    return (View) parent;
                }
                parent = parent.getParent();
            }
        
            return null;  // 如果没有找到 EpoxyRecyclerView,返回 null
        }

        private static boolean isInstanceOfClass(ViewParent view, String name) {
            Class<?> cls = view.getClass();
            //Log.d(TAG, "isInstanceOfClass cls:" + cls + " view:" + view);
            if (view instanceof ViewGroup) {
                for (; cls != Object.class; cls = cls.getSuperclass()) {
                    Log.d(TAG, "for loop cls:" + cls + " cls simple name:" + cls.getSimpleName() + " name:" + cls.getName());
                    if (name.equals(cls.getSimpleName())) {
                        if (DBG) {
                            Log.d(TAG, "############found isInstanceOfClass class:" + cls + " ############");
                        }
                        return true;
                    }
                }
            }
            return false;
        }
        
        public static int getItemPosition(Object epoxyRecyclerView, View item) {
            if (epoxyRecyclerView == null || item == null) {
                return -1;
            }

            try {
                // 获取 EpoxyRecyclerView 的 LayoutManager
                Method getLayoutManagerMethod = epoxyRecyclerView.getClass().getMethod("getLayoutManager");
                Object layoutManager = getLayoutManagerMethod.invoke(epoxyRecyclerView);

                if (layoutManager == null) {
                    return -1;
                }

                // 获取 item 的 position
                Method getChildAdapterPositionMethod = epoxyRecyclerView.getClass().getMethod("getChildAdapterPosition", View.class);
                int position = (int) getChildAdapterPositionMethod.invoke(epoxyRecyclerView, item);


                // 判断是否为第一个 item
                return position;
            } catch (Exception e) {
                e.printStackTrace();
            }

            return -1;
        }

        /**
         * 根据 position 获取 EpoxyRecyclerView 对应位置的 itemView
         *
         * @param epoxyRecyclerView EpoxyRecyclerView 对象
         * @param position          目标 position
         * @return 对应位置的 itemView,如果找不到则返回 null
         */
        public static View getItemViewByPosition(Object epoxyRecyclerView, int position) {
            if (epoxyRecyclerView == null || position < 0) {
                return null;
            }

            try {
                // 获取 LayoutManager
                Method getLayoutManagerMethod = epoxyRecyclerView.getClass().getMethod("getLayoutManager");
                Object layoutManager = getLayoutManagerMethod.invoke(epoxyRecyclerView);

                if (layoutManager == null) {
                    return null;
                }

                // 调用 findViewByPosition 方法
                Method findViewByPositionMethod = layoutManager.getClass().getMethod("findViewByPosition", int.class);
                return (View) findViewByPositionMethod.invoke(layoutManager, position);

            } catch (Exception e) {
                e.printStackTrace();
            }

            return null;
        }
    }
}

相关文章:

  • 【拼图——拼图类压缩dp,矩阵乘法,快速幂,DFS】
  • FinRL-DeepSeek: 大语言模型赋能的风险敏感型强化学习交易代理
  • 使用shardingsphere-proxy读写分离
  • Java网络编程封装
  • 如果二者隔离级别不一致,以哪个为主。例如@Transactional 隔离级别是RC,mysql是RR
  • MySQL安装
  • Docker 与 CI/CD:自动化构建和部署
  • MySQL数据库——索引结构之B+树
  • flowable 全生命周期涉及到的api及mysql表
  • nextjs项目搭建——头部导航
  • 【数论】—— 快速幂与扩展欧拉定理
  • 【Web开发】PythonAnyWhere免费部署Django项目
  • 第六次作业
  • python类型转换深浅拷贝
  • 了解Pipx:一个轻量但强大的Python工具
  • 如何在 SpringBoot 项目创建并使用 Redis 的详细介绍
  • 【漫话机器学习系列】103.学习曲线(Learning Curve)
  • 蓝桥杯之阶段考核
  • 跟李沐学AI:InstructGPT论文精读(SFT、RLHF)
  • 《Mycat核心技术》第17章:实现MySQL的读写分离
  • 商务网站建站/冯站长之家
  • 电子商务网站开发技术解决方案/谷歌收录提交入口
  • 小本本教你做网站/google浏览器官方
  • 自己做店招的网站/推广平台app
  • 网站促销活动策划/最近比较火的关键词
  • 响应式学校网站模板下载/国内重大新闻十条