问题
开机后Launcher默认无焦点,按键后焦点会出现,但不是在想要的位置上。
分析
Launcher.java中主动对指定View调用requestFocus()方法,重启后无法获取焦点,放在平时肯定是获取到焦点的。
试着Launcher.java拦截dispatchKeyEvent(),发现现象依然如此,因此判断开机后按键后的获取焦点并不在这里处理,这违背了之前所熟悉的焦点查找流程。
在ViewPostImeInputStage的processKeyEvent()方法没有处理,那应该是之前的InputStage处理了,于是打印线程调用栈
01-04 00:05:52.371 6046 6046 W System.err: at java.lang.Thread.dumpStack(Thread.java:1348)
01-04 00:05:52.371 6046 6046 W System.err: at android.view.FocusFinder.findNextFocusInAbsoluteDirection(FocusFinder.java:341)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.FocusFinder.findNextFocus(FocusFinder.java:269)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.FocusFinder.findNextFocus(FocusFinder.java:110)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.FocusFinder.findNextFocus(FocusFinder.java:80)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl.focusSearch(ViewRootImpl.java:6428)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl.leaveTouchMode(ViewRootImpl.java:4273)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl.ensureTouchModeLocally(ViewRootImpl.java:4206)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl.ensureTouchMode(ViewRootImpl.java:4188)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl.checkForLeavingTouchModeAndConsume(ViewRootImpl.java:6076)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl.-wrap1(Unknown Source:0)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$EarlyPostImeInputStage.processKeyEvent(ViewRootImpl.java:4698)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$EarlyPostImeInputStage.onProcess(ViewRootImpl.java:4679)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4318)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4371)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4337)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4464)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4345)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4521)
01-04 00:05:52.372 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4318)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4371)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4337)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4345)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4318)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4371)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4337)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4464)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4345)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4521)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4318)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6922)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6896)
01-04 00:05:52.373 6046 6046 W System.err: at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6853)
发现在EarlyPostImeInputStage阶段进行了一些处理,看调用栈里的方法就知道了原因,就是Android开机默认处于TouchMode,故即使requestFocus焦点也不会出现焦点,只有通过按键才可以退出TouchMode,那如何开机后进入到Launcher就有焦点存在,我的改法如下,如果有更好改法希望可以交流,谢谢!
解决
frameworks/base/core/java/android/view/ViewRootImpl.java
// 添加该方法调用原有逻辑退出TouchMode
/*
* @hide
*/
public void disableTouchMode() {
ensureTouchMode(false);
}
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
// breeze begin
private boolean disableTouchMode;
// breeze end
public void finishBindingItems() {
...
if (mLauncherCallbacks != null) {
mLauncherCallbacks.finishBindingItems(false);
}
if (LauncherAppState.PROFILE_STARTUP) {
Trace.endSection();
}
...
// breeze begin
View view = getWindow().peekDecorView();
if (view == null) {
return;
}
ViewRootImpl viewRootImpl = view.getViewRootImpl();
if(viewRootImpl != null && !disableTouchMode) {
Log.i("breeze","isInTouchMode , so disable it for myos");
viewRootImpl.disableTouchMode();
mAllAppsButton.requestFocus();
disableTouchMode = true;
}
// breeze end