- 在用方法是修改SurfaceView的updateSurface(),当前台app是com.kos.launcher,并请求app高度是屏幕高度(1080)时,忽略这次updateSurface。
- 上面方法总感觉不那么可靠。希望是在源头不让android认为切换了输入法。但溯源到Session::remove,不知道是谁调用它了。
远程桌面包括两个模块。一是录屏,即实现server发送桌面图像到client。二是模拟输入,即让server可以接收client发过来的键盘、鼠标指令。
在android,模拟输入技术用的是/dev/uinput,uinput创建的新设备放在/dev/input,这样在inputflinger看来,这设备已和其它输入设备没什么两样。更详细模拟输入看“libkosapi api”中“模拟输入”,在这里要说是,当用uinput创建新设备,会让android认为当前正发生了切换输入法。于是导致去销毁底部TaskBar,这TaskBar一销毁,给app可用的矩形高度就上升到整屏高度(1080)。于是乎前台app的surfaceChanged被调用了,myHeight参数值是1080。以下是用uinput创建的新设备,输出的部分logcat。
// 下面这条警告,表示输入通道对象“8b2b139 Taskbar (client)”被直接销毁而未通过输入管理器正常移除。 10:53:54.424 729-755 InputManager-JNI W Input channel object '8b2b139 Taskbar (client)' was disposed without first being removed with the input manager! // Config changes=20000500,mAppBounds高度(前台app可用高度)由997变成1080 10:53:54.432 729-755 ActivityTaskManager I Config changes=20000500 {1.0 ?mcc0mnc [zh_CN] ldltr sw785dp w1396dp h761dp 220dpi xlrg long land finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 1080) mMaxBounds=Rect(0, 0 - 1920, 1080) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.1 s.146 fontWeightAdjustment=0} 10:53:54.444 729-755 ActivityTaskManager W Current config: {1.0 ?mcc0mnc [zh_CN] ldltr sw785dp w1396dp h701dp 220dpi lrg long land finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 997) mMaxBounds=Rect(0, 0 - 1920, 1080) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.1 s.146 fontWeightAdjustment=0} unchanged for IME proc com.google.android.inputmethod.pinyin // 很快,又一个Config changes=20000500,只是mAppBounds高度由1080变成997 10:53:54.573 729-755 ActivityTaskManager I Config changes=20000500 {1.0 ?mcc0mnc [zh_CN] ldltr sw785dp w1396dp h701dp 220dpi lrg long land finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 997) mMaxBounds=Rect(0, 0 - 1920, 1080) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.1 s.180 fontWeightAdjustment=0} 10:53:54.587 729-755 ActivityTaskManager W Current config: {1.0 ?mcc0mnc [zh_CN] ldltr sw785dp w1396dp h761dp 220dpi xlrg long land finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 1080) mMaxBounds=Rect(0, 0 - 1920, 1080) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.1 s.180 fontWeightAdjustment=0} unchanged for IME proc com.google.android.inputmethod.pinyin
不清楚内中逻辑,很快的,发到前台app的又一个surfaceChanged过来了,此时myHeight参数值变成去掉TaskBar高度的997。
就在这很短时间,前台app的surface从997变成1080,又由1080变成997。这个短暂变化,要是app处理不好,容易造成问题。这里会问,用uinput创建新设备,能不能不让andorid认为是在切换输入法,或至少不让认为需要销毁TaskBar,从而触发后续改变前台app尺寸。
顺着不销毁TaskBar、不改变前台app尺寸这个目标,去尝试修改android代码。
一、uinput创建设备时的参数:absmax[ABS_Y]
用uinput创建设备,须要填一个高度参数。之前填的是屏幕高度1080。改为997后,结果没变化。
<aosp>/frameworks/native/libs/kosapi/sendinput.cpp ------ NativeConnection* NativeConnection::open(const char* name, const char* uniqueId, bool keyboard, int32_t screenWidth, int32_t screenHeight) { int32_t maxPointers = 1; int fd = ::open("/dev/uinput", O_WRONLY | O_NDELAY); ... uinp.absmin[ABS_X] = 0; uinp.absmax[ABS_X] = screenWidth - 1; uinp.absmin[ABS_Y] = 0; // scrrenHeight由1080,改为997。结果没变化。 uinp.absmax[ABS_Y] = screenHeight - 1; ... }
二、frameworks
“Config changes=20000500”这条logcat输出函数在ActivityTaskManagerService::updateGlobalConfigurationLocked。向上溯源,定位到WindowState::removeIfPossible()。
<aosp>/frameworks/base/services/core/java/com/android/server/wm/WindowState.java ------ class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState, InsetsControlTarget, InputTarget { @Override void removeIfPossible() { ... // disposeInputChannel会调用mInputChannel.dispose(),mInputChannel类型是InputChannel。 // InputChanne实现靠JNI,InputChannel::dispose对应cpp中NativeInputChannel::dispose。 // 内中mDisposeCallback是个函数指针, // 对应com_android_server_input_InputManagerService.cpp中的handleInputChannelDisposed, // 在这函数输出logcat:... was disposed without first being removed with ... disposeInputChannel(); ... if (needToSendNewConfiguration) { // 下面这个sendNewConfiguration会调用updateGlobalConfigurationLocked displayContent.sendNewConfiguration(); } // 注释掉下面这条updateFocusedWindowLocked,不能阻止回调前台app的surfaceChanged。 mWmService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS : UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } finally { Binder.restoreCallingIdentity(origId); } } }
不改变前台app尺寸,尝试几种修改。
- 不调用displayContent.sendNewConfiguration(),即不会执行updateGlobalConfigurationLocked。依旧要求改变前台app尺寸。
- 不调用mWmService.updateFocusedWindowLocked。依旧要求改变前台app尺寸。
可能吧,修改removeIfPossible,不让调某些函数,达不到目标。就想着怎么不调用removeIfPossible。这就要向上溯源。
<aosp>/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java WindowManagerService::removeWindow(Session session, IWindow client),调用了removeIfPossible <aosp/frameworks/base/services/core/java/com/android/server/wm/Session.java Session::remove(IWindow window),调用了WindowManagerService::removeWindow
但没找到是谁调用了Session::remove。在溯源Session::remove上遇到困难,只好退而求其次,阻止framworks调用surfaceChanged。能定位到,是SurfadeView的updateSurface在调用surfaceChanged。
<aosp>/frameworks/base/core/java/android/view/SurfaceView.java ------ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback { protected void updateSurface() { ... int myWidth = mRequestedWidth; if (myWidth <= 0) myWidth = getWidth(); int myHeight = mRequestedHeight; if (myHeight <= 0) myHeight = getHeight(); // 增加下面这个if判断 if (viewRoot.mBasePackageName.equals("com.kos.launcher") && myHeight == 1080) { return; } ... }
当前台app是com.kos.launcher,并要求app高度是屏幕高度时,忽略这次updateSurface。这个修改有几个问题。
- 直接忽略updateSurface,这种修改是否安全。
- 连接、断开远程桌面,界面还是会抖一下。
- 远程桌面时,前台app从com.kos.launcher切到其它app,再切回com.kos.launcher。这时com.kos.launcher和Task bar之间有条黑色横线,而且不会再消失。