Android 2.2 滑盖(lid)的影响
来源:互联网 发布:nginx重启服务 编辑:程序博客网 时间:2024/04/23 22:39
前段时间项目之中遇到了按键灯不亮的问题,稍微看了一下framework的代码,发现是因为滑盖的开关状态对其有影响。
在PhoneWindowManager中有定义:
boolean mLidOpen;
这里没有初始化,所以为false,而且硬件确实没有装滑盖,所以PhoneWindowManager对就不会对mLidOpen进行更新。
void readLidState() { try { int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID); //return -1 if (sw >= 0) { mLidOpen = sw == 0; } } catch (RemoteException e) { // Ignore } }
这里,mLidOpen也不会更新,输入事件不会主动上报。
/** {@inheritDoc} */ public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { case RawInputEvent.EV_SW: if (event.keycode == RawInputEvent.SW_LID) { // lid changed state mLidOpen = event.value == 0; boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); // ...省略部分代码 } } return false; }
因此,PhoneWindowManager会调用PowerManagerService的setKeyboardVisibility
/** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; mPowerManager.setKeyboardVisibility(lidOpen); // ...省略部分代码 }
在PowerManagerService中,会根据滑盖状态,决定键盘的可见状态。
public void setKeyboardVisibility(boolean visible) { synchronized (mLocks) { if (mKeyboardVisible != visible) { mKeyboardVisible = visible; // ...省略部分代码 } } }
也就是说,如果滑盖没有打开,键盘是不可见的(用过滑盖手机的都知道)。
这里要命的就是,PowerManagerService会根据键盘的可见状态,来决定亮不亮键盘灯,因此,我们的键盘灯一直是不亮的。
private int applyKeyboardState(int state) { int brightness = -1; if (!mKeyboardVisible) { brightness = 0; } // ...省略部分代码 }现在反思一下,我们要亮的是按键灯,不是键盘灯,现在两个灯等同为一个灯,键盘跟按键还是有区别的吧,android没有考虑到按键灯。所以我们只能把键盘灯当成按键灯使用了。
解决方法看起来很简单,就是回到问题的源头,在PhoneWindowManager中,就把mLidOpen的值初始化为true,这样它就一直会保持在true的状态,相当于滑盖一直是开的,因此键盘就一只是可见的,键盘灯就会亮了。
但是事情远远没有这么简单,自从改了这个以后,问题接踵而至,各种传感器失效,由于传感起也是刚开始调,因此不会不知道是就是因为改了这个值引起的。
1、重力传感器检测到方向有改变时,系统会调用PhoneWindowManager的rotationForOrientationLw方法,继而根据角度更新界面。
public int rotationForOrientationLw(int orientation, int lastRotation, boolean displayEnabled) { synchronized (mLock) { switch (orientation) { case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: //always return landscape if orientation set to landscape return mLandscapeRotation; case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: //always return portrait if orientation set to portrait return mPortraitRotation; } // case for nosensor meaning ignore sensor and consider only lid // or orientation sensor disabled //or case.unspecified if (mLidOpen) { return mLidOpenRotation; } // ...省略部分代码 } }
这里,因为 mLidOpen一直保持在true状态,因此屏幕旋转角度一直保持在mLidOpenRotation。任凭你怎么转,屏幕就是不旋转。mLidOpenRotation在frameworks/base/core/res/res/values/config.xml中读取。
因此可以感叹android的逻辑是多么严谨,如果你滑盖一直打开,说明就是有按键操作,这时候在转屏幕,是不合理的。
2、打电话时,如果脸贴近屏幕,接近传感器会将屏幕背光灯熄灭(省电,且防止误操作),这本身也是个很人性化的操作,没想到也会影响。在InCallScreen中
/* package */ void updateProximitySensorMode(Phone.State state) { if (proximitySensorModeEnabled()) { synchronized (mProximityWakeLock) { // turn proximity sensor off and turn screen on immediately if // we are using a headset, the keyboard is open, or the device // is being held in a horizontal position. boolean screenOnImmediately = (isHeadsetPlugged() || PhoneUtils.isSpeakerOn(this) || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn()) || mIsHardKeyboardOpen || mOrientation != AccelerometerListener.ORIENTATION_VERTICAL); if (((state == Phone.State.OFFHOOK) || mBeginningCall) && !screenOnImmediately) { // Phone is in use! Arrange for the screen to turn off // automatically when the sensor detects a close object. if (!mProximityWakeLock.isHeld()) { if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring..."); mProximityWakeLock.acquire(); } else { if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held."); } } } } }
这里的mIsHardKeyboardOpen会一直为true,因此就不会去acquire这个wake lock,因此靠近屏幕就不会熄背光灯。值得注意的是还依赖mOrientation,它是竖直方向才aquire,因为只有举起电话之时,才代表接起了电话。
mIsHardKeyboardOpen在onConfigurationChanged得到赋值
@Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { mIsHardKeyboardOpen = true; } else { mIsHardKeyboardOpen = false; } // Update the Proximity sensor based on keyboard state updateProximitySensorMode(); super.onConfigurationChanged(newConfig); }
因此,应用层根据Configuration中的hardKeyboardHidden来判断键盘是否可见。
这个值是在PhoneWindowManager中决定的,
/** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; mPowerManager.setKeyboardVisibility(lidOpen); config.hardKeyboardHidden = determineHiddenState(lidOpen, mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES, Configuration.HARDKEYBOARDHIDDEN_NO); config.navigationHidden = determineHiddenState(lidOpen, mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES, Configuration.NAVIGATIONHIDDEN_NO); config.keyboardHidden = (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput) ? Configuration.KEYBOARDHIDDEN_NO : Configuration.KEYBOARDHIDDEN_YES; }
因此,PowerManagerService可能跟Configuration针对键盘状态可能不同,取决于determineHiddenState的返回值,determineHiddenState综合了根据滑盖状态,和mLidKeyboardAccessibility,来决定hardKeyboardHidden的状态,mLidKeyboardAccessibility从config.xml中读取<!-- Indicate whether the lid state impacts the accessibility of the physical keyboard. 0 means it doesn't, 1 means it is accessible when the lid is open, 2 means it is accessible when the lid is closed. The default is 1. --> <integer name="config_lidKeyboardAccessibility">1</integer>
再看determineHiddenState,意思滑盖关闭的时候,如果mLidKeyboardAccessibility为1,代表键盘同时不可见。
private int determineHiddenState(boolean lidOpen, int mode, int hiddenValue, int visibleValue) { switch (mode) { case 1: return lidOpen ? visibleValue : hiddenValue; case 2: return lidOpen ? hiddenValue : visibleValue; } return visibleValue; }
这些写出来很容易,其实定位问题花了我好长时间,因此吸取一个教训,framework里面的千万不能随意改,不然会出大乱子。
- Android 2.2 滑盖(lid)的影响
- 添加LID的过程---操作NV的过程
- 我所知道的EC====>LID
- Android网易新闻评论盖楼效果的实现
- Android网易新闻评论盖楼效果的实现
- Android工程重构后不能被覆盖的问题
- MTK Android滑盖或翻盖处理驱动
- MTK Android滑盖或翻盖处理驱动
- 世博会的窨井盖!
- 关于Symbian滑盖手机的全屏问题
- mt2503[CB]MODEM里与CB有关的NVRAM,以及每个NVRAM LID的作用是什么
- android popwindow 解决opengl层叠上面的ui被覆盖的现象
- [Android]将一个视窗(windows)盖在整个Application的最上面
- [Android]将一个视窗(windows)盖在整个Application的最上面
- Android子控件超出父控件的范围被覆盖问题
- Android问题集锦---显示多个notification时PendingIntent的Intent被覆盖
- 解决使用android studio中的git update后报错当前未提交的代码被覆盖
- 解决使用android studio中的git update后报错当前未提交的代码被覆盖
- xen pci-passthrogh
- STL组件(components)之容器(container)
- xen pci-passthrough 2
- mingw如何使用VC编译的dll
- ubuntu 11.10 安装Oracle Database Enterprise/Standard Edition for Linux x86
- Android 2.2 滑盖(lid)的影响
- Nginx负载均衡配置文件详解之一(初级详解)
- 【十问十答】深度对话C++天才Andrei Alexandrescu
- VC--用DLL生成LIB文件
- java设计模式
- 测试我的第一篇博客
- 慎用++运算符,java和C++中的一个对比
- C++实现的可以安全的暂停、继续、停止线程的封装类
- 第七周任务1