MTK-Android12-系统设置一级菜单-适配遥控器

提示:MTK-Android12-系统设置一级菜单-适配遥控器

文章目录


前言-需求-存在的问题

前言-场景

Android12 MTK 平台,6769方案 的大屏产品,接遥控器 发现遥控器在系统设置一集菜单最下方的菜单可以获取的遥控器焦点,但是对用户不可见。 6769 本身是手机方案,拿来直接用作大屏商显产品,可能就本身存在一定问题,需要修复。 接入遥控器后,系统设置一级菜单可以实现遥控器下拉到最下方的一级菜单,用户可见。

存在问题

遥控器问题

如下,如果是白色遥控器 本身还可以点触效果,滑动页面 ,但是使用的是黑色遥控器就没有这个功能了。 那么就一定要通过 上下左右切换焦点的功能,达到每个功能性UI 焦点可达

系统源码问题

如下,实际问题:密码和账号、快霸 下面还有子菜单,遥控器焦点可达,但是UI不可见。 一定要用手上拉才能看见实际菜单。

一、参考资料

MTK-Android13-设置模块一级菜单添加遥控器功能 : 偏系统应用层适配,但是和当前版本不一致,可借鉴

Android软件适配遥控器需求-案例经验分享:偏应用层相关适配

MTK-Android12-适配蓝牙遥控器按键 : 偏系统层适配遥控器按键值、功能性适配。

二、实现方案

1、修改源码文件

文件路径: /vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/homepage/SettingsHomepageActivity.java

2、具体实践

修改方案

具体修改如下:

  • 屏蔽://initHomepageContainer();
java 复制代码
   private void initHomepageContainer() {
        final View view = findViewById(R.id.homepage_container);
        // Prevent inner RecyclerView gets focus and invokes scrolling.
        view.setFocusableInTouchMode(true);
        view.requestFocus();
    }
  • onCreate方法中,添加代码如下:
  • 给列表底部加留白,最后几项完全显示
java 复制代码
import android.view.View;
import android.view.ViewTreeObserver;
import androidx.core.widget.NestedScrollView;
import android.widget.FrameLayout; 
import android.util.Log;

 import android.view.ViewGroup;
 import androidx.recyclerview.widget.RecyclerView;
 import android.view.ViewParent;
 import android.graphics.Rect;



final ViewGroup mainContent = findViewById(R.id.main_content);

mainContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        mainContent.getViewTreeObserver().removeOnGlobalLayoutListener(this);

        // 找到列表
        RecyclerView recyclerView = findRecyclerView(mainContent);
        if (recyclerView == null) return;

        // 🔥 关键:给列表底部设置 400dp 留白,让最后几项可以完全滚动显示!
        int bottomPadding = (int) (getResources().getDisplayMetrics().density * 400);
        recyclerView.setPadding(
                recyclerView.getPaddingLeft(),
                recyclerView.getPaddingTop(),
                recyclerView.getPaddingRight(),
                bottomPadding // 底部加大量空白
        );
        recyclerView.setClipToPadding(false);
    }
});

修改原理

  • 屏蔽掉焦点占用
  • 直接给 RecyclerView 加足够的底部留白,让最后几项能完全滚上来。

三、实际效果

四、思路扩展-源码分析

1、实现方案和Android13 版本对比分析

  • 之前Mtk 平台Android13 版本,解决方案:屏蔽://initHomepageContainer(); 就可以了的,但是在Android12 版本中无效。

2、新方案畅享

方案难点

我们解决方案其实没有从UI滑动上面考虑来解决,只是兜底、保底 方案, 拼凑一个View 出来。 实际上 我们保证列表上划。

难点是:NestedScrollView 里面嵌套了 FrameLayoutFrameLayout中最终嵌套的是TopLevelSettings下面的各种PreferenceFragmentCompat,可以这么理解吧: 很难捕获到真正的焦点、焦点冲突了。

java 复制代码
NestedScrollView   ← **这个才能继续往上滑!**
   ↳ LinearLayout
      ↳ FrameLayout
         ↳ RecyclerView  ← **这个已经滑到底了,滑不动了!**
java 复制代码
  <androidx.core.widget.NestedScrollView
        android:id="@+id/main_content_scrollable_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="com.android.settings.widget.HomepageAppBarScrollingViewBehavior">

        <LinearLayout
            android:id="@+id/homepage_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <FrameLayout
                android:id="@+id/contextual_cards_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/contextual_card_side_margin"
                android:layout_marginEnd="@dimen/contextual_card_side_margin"/>

            <FrameLayout
                android:id="@+id/main_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:background="?android:attr/windowBackground"/>

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

新方案思路

基于焦点冲突问题,那么就是解决焦点冲突,所以可以尝试监听,然后找到对应的焦点,然后滑动对应的View. 这个方案可以自行研究,这里暂不讨论, 我自己尝试解决没有解决出来。

如下代码是调试代码,可以借鉴、找方向、定位问题:

java 复制代码
				
/*				
NestedScrollView scrollView = findViewById(R.id.main_content_scrollable_container);
scrollView.setNestedScrollingEnabled(false);

 getWindow().getDecorView().setOnFocusChangeListener((v, hasFocus) -> {
    View focusView = getCurrentFocus();
    if (focusView != null && focusView != scrollView) {
        scrollView.post(() -> {
			Log.d(TAG,"==========setOnFocusChangeListener smoothScrollBy===========");
            int[] pos = new int[2];
            focusView.getLocationInWindow(pos);
            scrollView.smoothScrollBy(0, pos[1] - 100);
        });
    }
});*/


 Log.d(TAG,"=======onCreate==============1111=");		

/*final NestedScrollView scrollView = findViewById(R.id.main_content_scrollable_container);
scrollView.setSmoothScrollingEnabled(true);

 getWindow().getDecorView().getViewTreeObserver().addOnGlobalFocusChangeListener((oldFocus, newFocus) -> {
    if (newFocus == null) return;

     int[] location = new int[2];
    newFocus.getLocationInWindow(location);
    int focusBottom = location[1] + newFocus.getHeight();
    int screenHeight = getResources().getDisplayMetrics().heightPixels;
	Log.d(TAG,"==========addOnGlobalFocusChangeListener focusBottom:"+focusBottom+"     screenHeight:"+screenHeight);
	//==========addOnGlobalFocusChangeListener focusBottom:1179     screenHeight:1008
    //==========addOnGlobalFocusChangeListener focusBottom:1297     screenHeight:1008
     if (focusBottom > screenHeight - 100) {
        scrollView.post(() -> {
            scrollView.smoothScrollBy(0, 300); 
        });
    }
});
*/

/*
final NestedScrollView scrollView = findViewById(R.id.main_content_scrollable_container);
scrollView.setSmoothScrollingEnabled(true);

getWindow().getDecorView().getViewTreeObserver().addOnGlobalFocusChangeListener((oldFocus, newFocus) -> {
    if (newFocus == null || scrollView == null) return;

    int[] location = new int[2];
    newFocus.getLocationOnScreen(location);
    int focusBottom = location[1] + newFocus.getHeight();
    int screenHeight = getResources().getDisplayMetrics().heightPixels;

    Log.d(TAG, "addOnGlobalFocusChangeListener focusBottom:" + focusBottom + " screenHeight:" + screenHeight);

    if (focusBottom > screenHeight - 100) {
        scrollView.post(() -> {
             int scrollY = newFocus.getTop() - scrollView.getTop();
			
         Log.d(TAG, "addOnGlobalFocusChangeListener scrollY:" + scrollY+"     newFocus.getTop():"+newFocus.getTop()+"   scrollView.getTop():"+scrollView.getTop());
			
            scrollView.scrollTo(0, scrollY);
        });
    }
});
*/


/*
final NestedScrollView scrollView = findViewById(R.id.main_content_scrollable_container);
final ViewGroup mainContent = findViewById(R.id.main_content);

mainContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        mainContent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        
         RecyclerView recyclerView = findRecyclerView(mainContent);
        if (recyclerView == null){
			  Log.d(TAG, "wfc  addOnGlobalLayoutListener recyclerView == null  return "  );

		   return;	
		} 

         getWindow().getDecorView().getViewTreeObserver().addOnGlobalFocusChangeListener((oldFocus, newFocus) -> {
            if (newFocus == null || recyclerView == null){
				
				 Log.d(TAG, "wfc addOnGlobalFocusChangeListener newFocus == null || recyclerView == null"  );

				return;
			}				

            int[] loc = new int[2];
            newFocus.getLocationInWindow(loc);
            int bottom = loc[1] + newFocus.getHeight();
            int screenHeight = getResources().getDisplayMetrics().heightPixels;

            Log.d(TAG, "wfc addOnGlobalFocusChangeListener  bottom: " + bottom + " screenHeight: " + screenHeight);

             if (bottom > screenHeight - 150) {
                recyclerView.post(() -> {
                     int position = recyclerView.getChildAdapterPosition(newFocus);
					 Log.d(TAG,"wfc ============== smoothScrollToPosition  position:"+position);
                 
					 recyclerView.scrollBy(0, 350);
					
                });
            }
        });
    }
});*/

/*
final NestedScrollView scrollView = findViewById(R.id.main_content_scrollable_container);

getWindow().getDecorView().getViewTreeObserver().addOnGlobalFocusChangeListener((oldFocus, newFocus) -> {
    if (newFocus == null) return;

     newFocus.post(() -> {
        newFocus.getWindowVisibleDisplayFrame(new Rect());
    });
});
*/

final ViewGroup mainContent = findViewById(R.id.main_content);

mainContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        mainContent.getViewTreeObserver().removeOnGlobalLayoutListener(this);

        RecyclerView recyclerView = findRecyclerView(mainContent);
        if (recyclerView == null) return;
        int bottomPadding = (int) (getResources().getDisplayMetrics().density * 400);
        recyclerView.setPadding(
                recyclerView.getPaddingLeft(),
                recyclerView.getPaddingTop(),
                recyclerView.getPaddingRight(),
                bottomPadding  
        );
        recyclerView.setClipToPadding(false);
    }
});












// ==========================================================
		
    }
	
	// modify by fangchen start

    private RecyclerView findRecyclerView(ViewGroup parent) {
      for (int i = 0; i < parent.getChildCount(); i++) {
        View child = parent.getChildAt(i);
        if (child instanceof RecyclerView) {
            return (RecyclerView) child;
        }
        if (child instanceof ViewGroup) {
            RecyclerView rv = findRecyclerView((ViewGroup) child);
            if (rv != null) return rv;
        }
      }
      return null;
   }
	
	// modify by fangchen end 

总结

  • 这里解决了Mtk平台 Android12 版本,系统设置不适配遥控器问题,针对性讨论了解决方案
  • 对比不同版本、不同的解决方案、找到实际解决方案并解决问题
  • 焦点问题才是核心,不太好调试,可以自行调试并解决。