问题描述
打开设置,进入应用,选择相机,清除相机相关权限,进入设置安全界面,设置锁屏方式为滑动解锁,点击power键进入锁屏界面,在锁屏界面,启动相机应用,待出现权限请求界面时,点击power键灭屏后再亮屏,出现提示框点击无效。
分析过程
当出现提示框点击无效的状态时,可能是由于无法获取到焦点导致,在尝试给予提示框Focus依然无法解决的情况下,通过dumpsys SurfaceFlinger查看系统图层,最底层为imageWallpaper,中间为packageinstaller的GrantPermissionsActivity界面,最上层为statusBar,且上层statusBar的高度为1280,即全屏显示,由于SystemUI显示的是最上方的状态栏StatusBar,布局仅在最上方,其他为最底层默认壁纸的界面,造成中间层GrantPermissionsActivity显示在界面上,但由于StatusBar获取到了整个屏幕的焦点,导致提示框无法获取到焦点,从而出现提示框出现却点击无效的现象。
根据上述分析可以判断此问题的原因在于状态栏在显示权限弹框界面时,高度获取有误,因此,需要查找状态栏高度未变化的原因。
查找到systemui设置状态栏高度的位置,根据applyHeight方法可以查看到,当状态栏处于下拉expanded状态时,获取到的高度为全屏显示,当处于收起状态时,状态栏的高度为48。
通过对applyHeight方法的分析,可以知道,在出现问题时,expanded未true导致mLpChanged.height的高度获取有误,而expanded是由isExpanded赋值的,以下是isExpanded的方法:
上图可以看到isExpanded由多个参数控制,添加log打印发现,在出现问题时,isKeyguardShowingAndNotOccluded获取到的值为true,通过该方法的名称,可以了解到此方法主要判断当前keyguard是否处于正在显示并未被阻挡状态,因为是直接进入的相机应用,实际上对Keyguard并未解锁,可以判断当前Keyguard应该处于showing的状态但因为权限框的原因,此时Keyguard应该处于occluded的状态才对,重点看一下KeyguardOccluded这个参数
KeyguardOccluded的值时通过setKeyguardOccluded方法获取到,因此,主要去查找setKeyguardOccluded的调用可以找到值出现问题的具体位置。
通过上述分析知道此问题主要是由于keyguardOccluded的值有误导致, 接下来主要跟踪一下keyguard的occluded的值,我们从framework层开始查找一下(主要是跟踪occluded的值)以下为framework层的时序图:
ensureActivitiesVisibleLocked主要负责Activity的状态,判断Activity是显示状态还是不可见状态,然后更新activity的状态,用户通过启动packageinstall应用,显示权限弹框,通过调用mKeyguardController.endActivityVisibilityUpdate将occluded的值传递下去,通过log查看到framework在传递值的过程中,是没有问题的,接下来主要分析应用层的传递,以下为应用层的时序图:
通过上图所显示的整个的调用流程,发现问题出在StatusBarKeyguardViewManage的setOccluded方法中,由于isInLaunchTransition为true导致该方法直接return,致使后面的mStatusBarWindowManager.setKeyguardOccluded未执行而未将参数传递下去导致,因为参数未传递,导致occluded的值未改变从而高度无法改变,isInLaunchTransition的值如下所示:
在启动camera应用时,为了用户体验会有一个过渡动画,而在应用启动完成时会调用onAnimationToSideEnded告知动画已完成,此时会将mIsLaunchTransitionRunning赋值为false,mIsLaunchTransitionFinished赋值为true,因此造成了isInLaunchTransition为true,出现后续问题。
解决方案
isInLaunchTransition为true导致的setKeyguardOccluded无法向下传递正确的参数,当isInLaunchTransition为true时,执行mStatusBarWindowManager.setKeyguardOcclude