问题描述:设备要横屏显示所有界面,但是Keyguard锁屏界面没有横屏显示,前提条件是设备没有Gsensor重力感应。
android版本:8.1
解决过程:从其他资料里学习和查看了keyguard的流程,找到了控制绘制方向的地方,问题随之解决。
系统在启动只会加载很多服务,SystemServer是所有服务的管家,他控制了系统服务的启动,在一切准备结束的时候,会调用各个服务的回调systemReady。
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
run开始后会调用很多很多服务的启动
try {
startBootstrapServices();
/// M: For mtk systemserver
sMtkSystemServerIns.startMtkBootstrapServices();
startCoreServices();
/// M: for mtk other service.
sMtkSystemServerIns.startMtkCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
throw ex;
} finally {}
最后很多服务启动后开始执行systemready
try {
wm.systemReady();
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
其中 windowmanager service的systemready会慢慢走到Phonewindowmanagerservice
// windowmanagerservice.java
public void systemReady() {
mPolicy.systemReady();
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
}
policy是个接口对象,
final WindowManagerPolicy mPolicy;
public interface WindowManagerPolicy{...}
实现这个接口的就是Phonewindowmanager
public class PhoneWindowManager implements WindowManagerPolicy
PhoneWindowManager 的systemready里
@Override
public void systemReady() {
// In normal flow, systemReady is called before other system services are ready.
// So it is better not to bind keyguard here.
mKeyguardDelegate.onSystemReady();
....
}
第一句话就是进入keyguard的systemready
public void onSystemReady() {
if (mKeyguardService != null) {
mKeyguardService.onSystemReady();
} else {
mKeyguardState.systemIsReady = true;
}
}
mKeyguardService的ready,走到了IKeyguardService,
oneway interface IKeyguardService
这里使用了AIDL 的IPC机制,最后的远程服务就是
KeyguardService extends Service
KeyguardService的mbinder就是在binder
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
在KeyguardService里有个KeyguardViewMediator
@Override
public void onCreate() {
((SystemUIApplication) getApplication()).startServicesIfNeeded();
mKeyguardViewMediator =
((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);
mKeyguardLifecyclesDispatcher = new KeyguardLifecyclesDispatcher(
Dependency.get(ScreenLifecycle.class),
Dependency.get(WakefulnessLifecycle.class));
}
在binder的接口里很多方法的实现都是靠这个KeyguardViewMediator,
public class KeyguardViewMediator extends SystemUI
在这里,IKeyguardService的onsystemready
@Override // Binder interface
public void onSystemReady() {
Trace.beginSection("KeyguardService.mBinder#onSystemReady");
checkPermission();
mKeyguardViewMediator.onSystemReady();
Trace.endSection();
}
接着去看看mKeyguardViewMediator的onsystemready
public void onSystemReady() {
synchronized (this) {
if (DEBUG) Log.d(TAG, "onSystemReady");
mSystemReady = true;
doKeyguardLocked(null);
mUpdateMonitor.registerCallback(mUpdateCallback);
mPowerOffAlarmManager.onSystemReady();
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
}
进入doKeyguardLocked(null);
private void doKeyguardLocked(Bundle options) {
//....省略上百行 方法的最后
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked(options);
}
方法的最后是showLocked()
private void showLocked(Bundle options) {
Trace.beginSection("KeyguardViewMediator#showLocked aqcuiring mShowKeyguardWakeLock");
if (DEBUG) Log.d(TAG, "showLocked");
// ensure we stay awake until we are finished displaying the keyguard
mShowKeyguardWakeLock.acquire();
Message msg = mHandler.obtainMessage(SHOW, options);
mHandler.sendMessage(msg);
Trace.endSection();
}
发送了message给handler去show
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW:
handleShow((Bundle) msg.obj);
break;
看看handleShow
private void handleShow(Bundle options) {
synchronized (KeyguardViewMediator.this) {
setShowingLocked(true);
mStatusBarKeyguardViewManager.show(options);
mHiding = false;
mWakeAndUnlocking = false;
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
userActivity();
if (mKeyguardDisplayManager != null) {
Log.d(TAG, "handle show call mKeyguardDisplayManager.show()") ;
mKeyguardDisplayManager.show();
} else {
Log.d(TAG, "handle show mKeyguardDisplayManager is null") ;
}
}
这里调用了两个show,第一个是mStatusBarKeyguardViewManager的show,里面带有bundle参数,
另一个调用了mKeyguardDisplayManager的show,执行了绘画的更新等操作
public void show() {
if (!mShowing) {
if (DEBUG) Slog.v(TAG, "show");
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
updateDisplays(true);
}
mShowing = true;
}
这里只是绘画相关,但是在绘画之前,那些参数的设置,一定产生了作用
去看看mStatusBarKeyguardViewManager的show
/**
* Show the keyguard. Will handle creating and attaching to the view manager
* lazily.
*/
public void show(Bundle options) {
if (DEBUG) Log.d(TAG, "show() is called.") ;
mShowing = true;
mStatusBarWindowManager.setKeyguardShowing(true);
mScrimController.abortKeyguardFadingOut();
reset(true /* hideBouncerWhenShowing */);
}
注释已经说明了,会去创建view
public void setKeyguardShowing(boolean showing) {
mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
}
这里的apply就是去更新状态,
private void apply(State state) {
applyKeyguardFlags(state);
applyForceStatusBarVisibleFlag(state);
applyFocusableFlag(state);
adjustScreenOrientation(state);
applyHeight(state);
applyUserActivityTimeout(state);
applyInputFeatures(state);
applyFitsSystemWindows(state);
applyModalFlag(state);
applyBrightness(state);
applyHasTopUi(state);
applySleepToken(state);
。。。。
}
刚好,看到了orientation,
private void adjustScreenOrientation(State state) {
if (state.isKeyguardShowingAndNotOccluded() || state.dozing) {
if (mKeyguardScreenRotation) {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
} else {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
}
} else {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
}
在这里,会去判断屏幕方向,如果是nosensor,那么结果就是,默认竖屏了,如果是user或者未指定,那么就是指定方向了,由于开机的时候系统给指定了user_rotate方向,那么在没有gsensor且方向不是nosensor的时候,就会去跟随user_rotate了,改了这里,只返回unspecified,锁屏的横屏问题就解决了,整个过程没有深度分析锁屏界面的各种细节,但是也经过了一个主线流程,这对以后的问题有了一个指导。
在这里看到了一个变量,mKeyguardScreenRotation
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
走进去看,
private boolean shouldEnableKeyguardScreenRotation() {
Resources res = mContext.getResources();
return SystemProperties.getBoolean("lockscreen.rot_override", false)
|| res.getBoolean(R.bool.config_enableLockScreenRotation);
}
原来这里设置了属性开关,决定是否开启锁屏旋转
在frameworks\base\core\res\res\values\config.xml里
false
所以,改了这里的enable就可以设置锁屏界面的方向了
关于user_rotation这个,需要去了解一下相关知识,这里不做解释。