概述
Android 10 的Box方案, 默认使用的是TvSettings作为系统设置,输入操作的习惯上是使用鼠标,键盘,遥控,日常的场景是没有问题,也不会出现本文中提及的问题。当外接的USB触摸屏后,出现无法点击WIFI密码框换出输入法进行输入密码操作。
问题:
从图1开始添加WIFI,并准备输入密码时,外接的USB触摸屏没有办法点击唤起输入法。
正常的情况应该如下图所示:
过程
在前面的一些文章中,对于无法点击或响应按键操作的问题,一般可以先查查焦点的问题:
View Hierarchy:
DecorView@661bdd7[WifiConnectionActivity]
android.widget.LinearLayout{abf86c4 V.E...... ........ 0,0-1920,1080}
android.view.ViewStub{e3449ad G.E...... ......I. 0,0-0,0 #10201a2 android:id/action_mode_bar_stub}
android.widget.FrameLayout{38444e2 V.E...... ........ 0,0-1920,1080 #1020002 android:id/content}
android.widget.FrameLayout{51a6073 V.E...... ........ 0,0-1920,1080 #7f0a0229 app:id/wifi_container}
androidx.leanback.app.GuidedStepRootLayout{1904b30 V.E...... ........ 0,0-1920,1080 #7f0a0105 app:id/guidedstep_root}
android.widget.FrameLayout{878d3a9 V.E...... ........ 0,0-1920,1080 #7f0a0104 app:id/guidedstep_background_view_root}
androidx.leanback.widget.NonOverlappingView{9a5cd2e V.ED..... ........ 0,0-1920,1080 #7f0a0103 app:id/guidedstep_background}
android.widget.LinearLayout{fb090cf V.E...... ........ 0,0-1920,1080 #7f0a00a0 app:id/content_frame}
androidx.leanback.widget.NonOverlappingFrameLayout{966ea5c V.E...... ........ 0,0-1231,1080 #7f0a009f app:id/content_fragment}
com.android.tv.settings.connectivity.setup.GuidanceRelativeLayout{b620165 V.E...... ........ 0,0-1231,1080}
android.widget.TextView{e458e3a V.ED..... ........ 168,374-1147,447 #7f0a00f1 app:id/guidance_title}
android.widget.TextView{fcf6aeb V.ED..... ........ 168,474-1147,503 #7f0a00ef app:id/guidance_description}
androidx.leanback.widget.NonOverlappingFrameLayout{aa65048 V.E...... ........ 1231,0-1919,1080 #7f0a0044 app:id/action_fragment_root}
androidx.leanback.widget.NonOverlappingView{4f64ee1 V.ED..... ........ 0,0-688,1080 #7f0a0043 app:id/action_fragment_background}
androidx.leanback.widget.NonOverlappingLinearLayout{bee5406 VFE...... ........ 0,0-688,1080 #7f0a0042 app:id/action_fragment}
android.widget.RelativeLayout{4b7cac7 V.E...... ........ 0,0-688,1080 #7f0a00ff app:id/guidedactions_root}
androidx.leanback.widget.NonOverlappingView{ef428f4 G.ED..... ......ID 0,0-0,0 #7f0a00fd app:id/guidedactions_list_background}
androidx.leanback.widget.GuidedActionsRelativeLayout{327f81d V.E...... ........ 0,0-688,1080 #7f0a00f3 app:id/guidedactions_content}
androidx.leanback.widget.VerticalGridView{90baa92 V.E...... ........ 0,0-348,1080 #7f0a00fb app:id/guidedactions_list}
android.widget.LinearLayout{6dc4c63 VFE...C.. ........ 0,103-348,528}
android.widget.FrameLayout{2a4e060 V.E...... ........ 0,293-348,365 #7f0a020f app:id/text_input_wrapper}
android.widget.EditText{6d0f919 VFED..... ........ 24,0-324,72 #7f0a00fa app:id/guidedactions_item_title}
android.widget.CheckBox{535ddde VFED..C.. ........ 14,377-146,425 #7f0a01ac app:id/password_checkbox}
androidx.leanback.widget.NonOverlappingView{93d4bbf G.ED..... ......ID 0,0-0,0 #7f0a0102 app:id/guidedactions_sub_list_background}
androidx.leanback.widget.VerticalGridView{e7a28c IFE...... ......I. 0,432-688,432 #7f0a0101 app:id/guidedactions_sub_list}
android.widget.RelativeLayout{a6f0dd5 V.E...... ........ 688,0-688,1080 #7f0a0100 app:id/guidedactions_root2}
androidx.leanback.widget.NonOverlappingView{f3df9ea V.ED..... ......ID 0,0-0,1080 #7f0a00fe app:id/guidedactions_list_background2}
androidx.leanback.widget.NonOverlappingFrameLayout{484e4db V.E...... ......ID 0,0-0,1080 #7f0a00f4 app:id/guidedactions_content2}
androidx.leanback.widget.VerticalGridView{6b25b78 V.E...... ......ID 0,0-0,1080 #7f0a00fc app:id/guidedactions_list2}
很明显android.widget.EditText{6d0f919 VFED… … 24,0-324,72 #7f0a00fa app:id/guidedactions_item_title} 不可点击.
通过ID找到相关的代码:
$ grep -r "guidedactions_item_title" packages/apps/TvSettings/Settings
packages/apps/TvSettings/Settings/res/layout/setup_text_input_item.xml: android:id="@+id/guidedactions_item_title"
packages/apps/TvSettings/Settings/res/layout/setup_password_item.xml: android:id="@+id/guidedactions_item_title"
packages/apps/TvSettings/Settings/src/com/android/tv/settings/connectivity/util/GuidedActionsAlignUtil.java: androidx.leanback.R.id.guidedactions_item_title);
packages/apps/TvSettings/Settings/src/com/android/tv/settings/util/GuidedActionsAlignUtil.java: androidx.leanback.R.id.guidedactions_item_title);
packages/apps/TvSettings/Settings/res/layout/setup_password_item.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text_input_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/setup_list_item_height"
android:layout_alignParentStart="true"
android:layout_marginTop="@dimen/setup_action_vertical_offset"
android:background="@drawable/setup_text_input_background"
android:elevation="@dimen/setup_elevation"
android:gravity="start|center_vertical"
android:paddingEnd="@dimen/setup_list_item_padding"
android:paddingStart="@dimen/setup_list_item_padding">
<EditText
android:id="@+id/guidedactions_item_title"
style="@style/Setup.Action.TextInput"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:gravity="center_vertical"
android:imeOptions="actionNext|flagNoExtractUi"
android:inputType="text">
</EditText>
</FrameLayout>
<CheckBox
android:id="@+id/password_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/setup_obfuscation_margin_start"
android:layout_marginTop="@dimen/setup_obfuscation_margin_top"
android:buttonTint="@color/setup_list_item_background_focused"
android:buttonTintMode="src_in"
android:text="@string/text_obfuscation_toggle_caption" />
</LinearLayout>
@Override
public GuidedActionsStylist onCreateActionsStylist() {
return new GuidedActionsStylist() {
@Override
public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
super.onBindViewHolder(vh, action);
if (action.getId() == GuidedAction.ACTION_ID_CONTINUE) {
PasswordViewHolder viewHolder = (PasswordViewHolder) vh;
mTextInput = (EditText) viewHolder.getTitleView();
mTextInput.setClickable(true);
mTextInput.setFocusableInTouchMode(true);
mCheckBox = viewHolder.mCheckbox;
mCheckBox.setOnClickListener(view -> {
updatePasswordInputObfuscation();
EnterPasswordFragment.this.openInEditMode(action);
});
mCheckBox.setChecked(mUserChoiceInfo.isPasswordHidden());
updatePasswordInputObfuscation();
openInEditMode(action);
}
}
}
@Override
public int onProvideItemLayoutId() {
return R.layout.setup_password_item;
}
}
增加
mTextInput.setClickable(true);
mTextInput.setFocusableInTouchMode(true);
编译,解决!
另一种尝试
在这之前,尝试过在XML中设置:
<EditText
android:clickable="true"
android:focusableInTouchMode="true"
>
结果:无效??
反复确认了layout文件的正确性无果。
从代码中去一个个追查并不现实,取了个巧,自定一个EditText替换了默认的,并重写了setClickable函数,从中打印出调用的堆栈得知,在GuidedActionsStylist.onBindViewHolder中确实调用了。
GuidedActionsStylist 位于androidx中,
packages/apps/TvSettings/Settings/Android.mk
LOCAL_PACKAGE_NAME := TvSettings
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_TAGS := optional
LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PRIVILEGED_MODULE := true
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.recyclerview_recyclerview \
androidx.preference_preference \
androidx.appcompat_appcompat \
androidx.legacy_legacy-preference-v14 \
androidx.leanback_leanback-preference \
androidx.leanback_leanback \
androidx.lifecycle_lifecycle-extensions \
androidx-constraintlayout_constraintlayout \
对应的jar包路径:
out/target/common/obj/JAVA_LIBRARIES/androidx.leanback_leanback_intermediates/classes.jar
顺便看下源码:
public ViewHolder(@NonNull View v, boolean isSubAction) {
super(v);
mContentView = v.findViewById(R.id.guidedactions_item_content);
mTitleView = (TextView) v.findViewById(R.id.guidedactions_item_title);
mActivatorView = v.findViewById(R.id.guidedactions_activator_item);
mDescriptionView = (TextView) v.findViewById(R.id.guidedactions_item_description);
mIconView = (ImageView) v.findViewById(R.id.guidedactions_item_icon);
mCheckmarkView = (ImageView) v.findViewById(R.id.guidedactions_item_checkmark);
mChevronView = (ImageView) v.findViewById(R.id.guidedactions_item_chevron);
mIsSubAction = isSubAction;
v.setAccessibilityDelegate(mDelegate);
}
/**
* Binds a {@link ViewHolder} to a particular {@link GuidedAction}.
* @param vh The view holder to be associated with the given action.
* @param action The guided action to be displayed by the view holder's view.
* @return The view to be added to the caller's view hierarchy.
*/
public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
vh.mAction = action;
if (vh.mTitleView != null) {
vh.mTitleView.setInputType(action.getInputType());
vh.mTitleView.setText(action.getTitle());
vh.mTitleView.setAlpha(action.isEnabled() ? mEnabledTextAlpha : mDisabledTextAlpha);
vh.mTitleView.setFocusable(false);
vh.mTitleView.setClickable(false);
vh.mTitleView.setLongClickable(false);
if (BuildCompat.isAtLeastP()) {
if (action.isEditable()) {
vh.mTitleView.setAutofillHints(action.getAutofillHints());
} else {
vh.mTitleView.setAutofillHints((String[]) null);
}
} else if (VERSION.SDK_INT >= 26) {
// disable autofill below P as dpad/keyboard is not supported
vh.mTitleView.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);
}
}
//....
}
从上面的代码可以看出,使用了GuidedActionsStylist后,guidedactions_item_title这个ID的控件会被置为不可点击。
刚好就是前面提及的文本输入框,对头!
引用
android:focusable和android:focusableInTouchMode的区别
GuidedActionsStylist
AndroidX GitHub
AOSP AndroidX Contribution Guide