Android T about screen rotation(二)
需求:客户因为模具问题,屏幕方向需要动态的变动.(方向: 0 , 90 , 180 ,270)
拆分:设备开机过程中图像显示可分为三个阶段,boot logo(1)->kernel logo(2),这一段的处理需要驱动层,所以暂时忽略.
开机动画 Bootanimation(3)阶段 和 Home Launcher应用显示(4)阶段是需要修改的.
因为是动态的,有涉及到cpp部分,一般用系统属性保存:persist.customer.set.orientation=0
Bootanimation
./frameworks/base/cmds/bootanimation/BootAnimation.cpp
/**
* readyToRun()负责构建开机动画,进入readyToRun()中 就来加载显示每一帧动画
*
* createSurface()负责绘制开机动画页面
*/
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
if (mDisplayToken == nullptr)
return NAME_NOT_FOUND;
DisplayMode displayMode;
const status_t error =
SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
if (error != NO_ERROR)
return error;
mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
ui::Size resolution = displayMode.resolution;
resolution = limitSurfaceSize(resolution.width, resolution.height);
+ //add text
+ char cOrientation [PROPERTY_VALUE_MAX];
+ property_get("persist.customer.set.orientation",cOrientation,"0");
+ int temp_orientation = atoi(cOrientation);
+
+ SurfaceComposerClient::Transaction t;
+
+ int temp_width = 0;
+ int temp_height = 0;
+
+ if(temp_orientation == 90){
+ temp_width = resolution.getHeight();
+ temp_height = resolution.getWidth();
+ Rect destRect(temp_width, temp_height);
+ t.setDisplayProjection(mDisplayToken, ui::ROTATION_90, destRect, destRect);
+ ALOGD("BootAnimation rotation is 90");
+ }else if(temp_orientation == 180){
+ Rect destRect(temp_width, temp_height);
+ t.setDisplayProjection(mDisplayToken, ui::ROTATION_180, destRect, destRect);
+ ALOGD("BootAnimation rotation is 180");
+ }else if(temp_orientation == 270){
+ temp_width = resolution.getHeight();
+ temp_height = resolution.getWidth();
+ Rect destRect(temp_width, temp_height);
+ t.setDisplayProjection(mDisplayToken, ui::ROTATION_270, destRect, destRect);
+ ALOGD("BootAnimation rotation is 270");
+ }
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
-
- SurfaceComposerClient::Transaction t;
+ //add text
// this guest property specifies multi-display IDs to show the boot animation
// multiple ids can be set with comma (,) as separator, for example:
...
}
//系统自带根据ro.bootanim.set_orientation_<display_id> 旋转屏幕动画方向
// Rotate the boot animation according to the value specified in the sysprop ro.bootanim.set_orientation_<display_id>.
// Four values are supported: ORIENTATION_0,ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270.
// If the value isn't specified or is ORIENTATION_0, nothing will be changed.
// This is needed to support having boot animation in orientations different from the natural
// device orientation. For example, on tablets that may want to keep natural orientation
// portrait for applications compatibility and to have the boot animation in landscape.
void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() {
const auto orientation = parseOrientationProperty();
if (orientation == ui::ROTATION_0) {
// Do nothing if the sysprop isn't set or is set to ROTATION_0.
return;
}
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(mWidth, mHeight);
std::swap(mInitWidth, mInitHeight);
mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight);
}
Rect displayRect(0, 0, mWidth, mHeight);
Rect layerStackRect(0, 0, mWidth, mHeight);
SurfaceComposerClient::Transaction t;
t.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect);
t.apply();
}
ui::Rotation BootAnimation::parseOrientationProperty() {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
if (displayIds.size() == 0) {
return ui::ROTATION_0;
}
const auto displayId = displayIds[0];
const auto syspropName = [displayId] {
std::stringstream ss;
ss << "ro.bootanim.set_orientation_" << displayId.value;
return ss.str();
}();
const auto syspropValue = android::base::GetProperty(syspropName, "ORIENTATION_0");
if (syspropValue == "ORIENTATION_90") {
return ui::ROTATION_90;
} else if (syspropValue == "ORIENTATION_180") {
return ui::ROTATION_180;
} else if (syspropValue == "ORIENTATION_270") {
return ui::ROTATION_270;
}
return ui::ROTATION_0;
}
applications
动画的屏幕方向,一阶段是由上面的代码决定,二阶段由Framework display决定
frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
+ private int mCustomerRotation = Surface.ROTATION_0;//add text
@VisibleForTesting
DisplayRotation(WindowManagerService service, DisplayContent displayContent,
DisplayAddress displayAddress, DisplayPolicy displayPolicy,
DisplayWindowSettings displayWindowSettings, Context context, Object lock,
@NonNull DeviceStateController deviceStateController) {
mService = service;
mDisplayContent = displayContent;
...
+ //add text
+ int temp_orientation = SystemProperties.getInt("persist.customer.set.orientation", 0);
+ if (temp_orientation == 0) {
+ mCustomerRotation = Surface.ROTATION_0;
+ } else if (temp_orientation == 90) {
+ mCustomerRotation = Surface.ROTATION_90;
+ } else if (temp_orientation == 180) {
+ mCustomerRotation = Surface.ROTATION_180;
+ } else if (temp_orientation == 270) {
+ mCustomerRotation = Surface.ROTATION_270;
+ }
+ mRotation = mCustomerRotation;//end replace
+ //add text
+
//观察 user_rotation
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
mOrientationListener =
new OrientationListener(mContext, uiHandler, defaultRotation);
mOrientationListener.setCurrentRotation(mRotation);
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
if (mSupportAutoRotation && mContext.getResources().getBoolean(
R.bool.config_windowManagerHalfFoldAutoRotateOverride)) {
mFoldController = new FoldController();
} else {
mFoldController = null;
}
} else {
mFoldController = null;
}
}
boolean updateRotationUnchecked(boolean forceUpdate) {
final int displayId = mDisplayContent.getDisplayId();
...
final int oldRotation = mRotation;
final int lastOrientation = mLastOrientation;
- int rotation = rotationForOrientation(lastOrientation, oldRotation);
+ int rotation = mCustomerRotation;//rotationForOrientation(lastOrientation, oldRotation);//add text
// Use the saved rotation for tabletop mode, if set.
if (mFoldController != null && mFoldController.shouldRevertOverriddenRotation()) {
int prevRotation = rotation;
...
}
@Surface.Rotation
int rotationForOrientation(@ScreenOrientation int orientation,
@Surface.Rotation int lastRotation) {
...
//关于这里的判断,自己可以根据需求旋转条件
+ //add text
+ if(true){
+ return mCustomerRotation;
+ }
+ //add text
+
if (isFixedToUserRotation()) {
return mUserRotation;
}
}
/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
@ScreenOrientation
@Override
int getOrientation() {
+ //add text
+ int mCustomerRotation = 0;
+ int temp_orientation = SystemProperties.getInt("persist.customer.set.orientation", 0);
+ if (temp_orientation == 0) {
+ mCustomerRotation = Surface.ROTATION_0;
+ return mCustomerRotation;
+ } else if (temp_orientation == 90) {
+ mCustomerRotation = Surface.ROTATION_90;
+ return mCustomerRotation;
+ } else if (temp_orientation == 190) {
+ mCustomerRotation = Surface.ROTATION_180;
+ return mCustomerRotation;
+ } else if (temp_orientation == 270) {
+ mCustomerRotation = Surface.ROTATION_270;
+ return mCustomerRotation;
+ }
+ //add text
if (mWmService.mDisplayFrozen) {
if (mWmService.mPolicy.isKeyguardLocked()) {
//是否允许设备通过加速器(G-sensor)在所有四个方向自动旋转屏幕
/frameworks/base/core/res/res/values/config.xml
<!-- If true, the screen can be rotated via the accelerometer in all 4
rotations as the default behavior. -->
- <bool name="config_allowAllRotations">false</bool>
+ <bool name="config_allowAllRotations">true</bool>
<!-- If true, the direction rotation is applied to get to an application's requested
orientation is reversed. Normally, the model is that landscape is
about SurfaceFlinger
SurfaceFlinger是Android系统中负责屏幕显示内容合成的服务,它接收来自多个应用程序和系统服务的图像缓冲区,
根据它们的位置、大小、透明度、Z轴顺序等属性,将它们合成到一个最终的缓冲区中,然后发送到显示设备上
修改getPhysicalDisplayOrientation 显示方向,也可以实现上面的效果.
如果要动态的,就要用到系统属性,但是可能会遇到针对数据分区加密导致的开机时无法读取系统属性问题.
如何解决,(修改init.mount_all_early.rc和fstab.in)参考:RK平台android12 动态调整屏幕方向
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId,
bool isPrimary) const {
/*const auto id = PhysicalDisplayId::tryCast(displayId);
if (!id) {
return ui::ROTATION_0;
}
if (getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) {
switch (getHwComposer().getPhysicalDisplayOrientation(*id)) {
case Hwc2::AidlTransform::ROT_90:
return ui::ROTATION_90;
case Hwc2::AidlTransform::ROT_180:
return ui::ROTATION_180;
case Hwc2::AidlTransform::ROT_270:
return ui::ROTATION_270;
default:
return ui::ROTATION_0;
}
}
if (isPrimary) {
using Values = SurfaceFlingerProperties::primary_display_orientation_values;
switch (primary_display_orientation(Values::ORIENTATION_0)) {
case Values::ORIENTATION_90:
return ui::ROTATION_90;
case Values::ORIENTATION_180:
return ui::ROTATION_180;
case Values::ORIENTATION_270:
return ui::ROTATION_270;
default:
break;
}
}*/
return ui::ROTATION_270;
}
void SurfaceFlinger::startBootAnim() {
// Start boot animation service by setting a property mailbox
// if property setting thread is already running, Start() will be just a NOP
mStartPropertySetThread->Start();
// Wait until property was set
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
}
SurfaceFlinger的原理
Android显示系统SurfaceFlinger详解 超级干货
正点原子RK3588开发板Android系统屏幕显示方向配置