在开发android智能TV项目时,遇到一个应用的问题,使用ListView的所有UI在第一次打开时均没有焦点,各种方法试尽,前前后后经历N位工程师均没有解决掉,就这样过了半年,一堆相关问题依然挂在那里...
后来想到是不是touch mode的问题呢?
可以看到isInTouchMode的判断,继续跟进到View.java
继续查看ViewRootImpl.java
找到session.java
最后知道是WindowManagerService.java中通过 setInTouchMode来设置 mInTouchMode,而起动作是在ViewRootImpl.java中通过ensureTouchMode来实作
IR有动作时,KeyCode会分发到View上处理,进而调用 ensureTouchMode 设置系统离开TouchMode,坑爹的手机触摸模式...
总结分析:开机后第一无法获取焦点,任意按键后可以获取;开机后android默认是在Touch模式,任意按键后,系统离开TouchMode,所以就恢复正常;
解决方法:考虑到TV的特殊性,所以在打开ListView的时候调用 Instramention.setInTouchMode(false);
后来想到是不是touch mode的问题呢?
ListView.setSelection->setSelectionFromTop(position, 0);
public void setSelectionFromTop(int position, int y) {
if (mAdapter == null) {
return;
}
if (!isInTouchMode()) {
position = lookForSelectablePosition(position, true);
if (position >= 0) {
setNextSelectedPositionInt(position);
}
} else {
mResurrectToPosition = position;
}
if (position >= 0) {
mLayoutMode = LAYOUT_SPECIFIC;
mSpecificTop = mListPadding.top + y;
if (mNeedSync) {
mSyncPosition = position;
mSyncRowId = mAdapter.getItemId(position);
}
if (mPositionScroller != null) {
mPositionScroller.stop();
}
requestLayout();
}
}
可以看到isInTouchMode的判断,继续跟进到View.java
@ViewDebug.ExportedProperty
public boolean isInTouchMode() {
if (mAttachInfo != null) {
return mAttachInfo.mInTouchMode;
} else {
return ViewRootImpl.isInTouchMode();
}
}
继续查看ViewRootImpl.java
static boolean isInTouchMode() {
IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
if (windowSession != null) {
try {
return windowSession.getInTouchMode();
} catch (RemoteException e) {
}
}
return false;
}
找到session.java
public boolean getInTouchMode() {
synchronized(mService.mWindowMap) {
return mService.mInTouchMode;
}
}
最后知道是WindowManagerService.java中通过 setInTouchMode来设置 mInTouchMode,而起动作是在ViewRootImpl.java中通过ensureTouchMode来实作
public void setInTouchMode(boolean mode) {
synchronized(mWindowMap) {
mInTouchMode = mode;
}
}
boolean ensureTouchMode(boolean inTouchMode) {
if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
+ "touch mode is " + mAttachInfo.mInTouchMode);
if (mAttachInfo.mInTouchMode == inTouchMode) return false;
// tell the window manager
try {
mWindowSession.setInTouchMode(inTouchMode);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
// handle the change
return ensureTouchModeLocally(inTouchMode);
}
IR有动作时,KeyCode会分发到View上处理,进而调用 ensureTouchMode 设置系统离开TouchMode,坑爹的手机触摸模式...
总结分析:开机后第一无法获取焦点,任意按键后可以获取;开机后android默认是在Touch模式,任意按键后,系统离开TouchMode,所以就恢复正常;
解决方法:考虑到TV的特殊性,所以在打开ListView的时候调用 Instramention.setInTouchMode(false);