前言
之前做过的默认横屏大多是强制性的,静止后自动旋转,因为没有重力传感器。之前的改革过于暴力和不正统,
这次仔细研究 android 水平和垂直屏幕控制相关代码,并整理适当的修改方案。
在大多数情况下,垂直屏幕水平使用是一种常见的应用场景,这应该可以节省成本,但给系统软件带来了很多麻烦。
谷歌和 MTK 屏幕旋转做得很完美, 这里就以 MTK 平台 android11 最新源码分析。
1、Uboot Logo方向控制(启动第一屏)
MTK 的 UbootLogo 绘制在 lk 在代码中,它是一个相对完美的框架,无论版本如何迭代,几乎没有变化。
代码路径如下
void init_fb_screen() {
dprintf(INFO, "[lk logo: %s %d]\n",__FUNCTION__,__LINE__); unsigned int fb_size = mt_get_fb_size(); logo_addr = mt_get_logo_db_addr(); phical_screen.width = CFG_DISPLAY_WIDTH; phical_screen.height = CFG_DISPLAY_HEIGHT; phical_screen.fb_size = fb_size; phical_screen.fill_dst_bits = CFG_DISPLAY_BPP; phical_screen.bits_per_pixel = CFG_DISPLAY_BPP; // in JB2.MP need to allign width and height to 32 ,but jb5.mp needn't phical_screen.needAllign = 1; phical_screen.allignWidth = ALIGN_TO(CFG_DISPLAY_WIDTH, MTK_FB_ALIGNMENT); /* In GB, no need to adjust 180 showing logo ,for fb driver dealing the change */ /* but in JB, need adjust it for screen 180 roration */ phical_screen.need180Adjust = 0; // need sync with chip driver dprintf(INFO, "[lk logo: %s %d]MTK_LCM_PHYSICAL_ROTATION = %s\n",__FUNCTION__,__LINE__, MTK_LCM_PHYSICAL_ROTATION); if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "270", 3)) {
phical_screen.rotation = 270;
} else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "90", 2)) {
phical_screen.rotation = 90;
} else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "180", 3) && (phical_screen.need180Adjust == 1)) {
phical_screen.rotation = 180;
} else {
phical_screen.rotation = 0;
}
看到核心方法 init_fb_screen(),其中根据 来设置 ubootlogo 旋转角度,说明 MTK 已经做好了兼容
我们只需找到 配置为想要的方向角度即可。
经过搜索在 中找到定义
MTK_LCM_PHYSICAL_ROTATION = 270
lk 的编译规则定义在
include project/$(PROJECT).mk
include make/rat_config.mk
include target/$(TARGET)/rules.mk
include dev/rules.mk
include platform/$(PLATFORM)/rules.mk
ifeq ($(MTK_EMMC_SUPPORT), yes)
2、Kernel Logo(开机第二屏)方向控制
KernelLogo 的绘制在 libshowlogo 库中,调用 show_kernel_logo()
void bootlogo_show_kernel()
{
KPOC_LOGI("[ChargingAnimation: %s %d] show kernel logo \n",__FUNCTION__,__LINE__);
show_kernel_logo();
}
int anim_fb_init(void)
{
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]\n",__FUNCTION__,__LINE__);
}
fb_fd = open(FB_NODE_PATH, O_RDWR);
if(fb_fd < 0)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[libshowlogo: %s %d]open dev file fail, errno = %d \n",__FUNCTION__,__LINE__ , errno);
}
close(fb_fd);
error_flag = 1;
return -1;
}
......
phical_screen.bits_per_pixel = vinfo.bits_per_pixel;
phical_screen.fill_dst_bits = vinfo.bits_per_pixel;
phical_screen.red_offset = vinfo.red.offset;
phical_screen.blue_offset = vinfo.blue.offset;
phical_screen.width = vinfo.xres;
phical_screen.height = vinfo.yres;
phical_screen.allignWidth = finfo.line_length/(vinfo.bits_per_pixel/8);
phical_screen.needAllign = 1;
phical_screen.need180Adjust = 1;
phical_screen.fb_size = fb_size;
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]MTK_LCM_PHYSICAL_ROTATION = %s\n",__FUNCTION__,__LINE__, MTK_LCM_PHYSICAL_ROTATION);
}
int rotation = getRotation();
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]rotation = %d\n",__FUNCTION__,__LINE__, rotation);
}
if(ORIENTATION_270 == rotation){
//270
phical_screen.rotation = 270;
} else if(ORIENTATION_90 == rotation){
//90
phical_screen.rotation = 90;
} else if((ORIENTATION_180 == rotation) && (phical_screen.need180Adjust == 1)){
//180
phical_screen.rotation = 180;
} else {
phical_screen.rotation = 0;
}
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo]phical_screen: width= %d,height= %d,bits_per_pixel =%d,needAllign = %d,allignWidth=%d rotation =%d ,need180Adjust = %d\n",
phical_screen.width, phical_screen.height,
phical_screen.bits_per_pixel, phical_screen.needAllign,
phical_screen.allignWidth, phical_screen.rotation, phical_screen.need180Adjust);
SLOGD("[libshowlogo: %s %d]show old animtion= 1, running show_animationm_ver %d\n",__FUNCTION__,__LINE__, show_animationm_ver);
SLOGD("[libshowlogo: %s %d]draw_anim_mode = 1, running mode %d\n",__FUNCTION__,__LINE__, draw_anim_mode);
}
return 0;
}
void show_kernel_logo()
{
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]show kernel logo, index = 38 \n",__FUNCTION__,__LINE__);
}
if (error_flag == 0) {
anim_show_logo(kernel_logo_position);
}
}
在调用绘制之前进行了 fb_fd 初始化,核心方法为 anim_fb_init(void),其中根据 int rotation = getRotation();
来设置 kernellogo 旋转角度,找到 getRotation() 实现方法位于
#include "utils.h"
#include <SurfaceFlingerProperties.sysprop.h>
int getRotation() {
using RotationValues = android::sysprop::SurfaceFlingerProperties::primary_display_orientation_values;
auto rotation_temp = android::sysprop::SurfaceFlingerProperties::primary_display_orientation();
int rotation = Rotation::ORIENTATION_0;
if (rotation_temp.has_value()) {
switch (*rotation_temp) {
case RotationValues::ORIENTATION_0:
rotation = Rotation::ORIENTATION_0;
break;
case RotationValues::ORIENTATION_90:
rotation = Rotation::ORIENTATION_90;
break;
case RotationValues::ORIENTATION_180:
rotation = Rotation::ORIENTATION_180;
break;
case RotationValues::ORIENTATION_270:
rotation = Rotation::ORIENTATION_270;
break;
default:
break;
}
}
return rotation;
}
从中读取 prop 属性 primary_display_orientation_values 对应值,继续寻找在哪里赋值
primary_display_orientation_values定义
位于
ifneq ($(strip $(MTK_LCM_PHYSICAL_ROTATION)),)
ifeq ($(strip $(MTK_LCM_PHYSICAL_ROTATION)), 90)
PRODUCT_PROPERTY_OVERRIDES += ro.surface_flinger.primary_display_orientation=ORIENTATION_90
else ifeq ($(strip $(MTK_LCM_PHYSICAL_ROTATION)), 180)
PRODUCT_PROPERTY_OVERRIDES += ro.surface_flinger.primary_display_orientation=ORIENTATION_180
else ifeq ($(strip $(MTK_LCM_PHYSICAL_ROTATION)), 270)
PRODUCT_PROPERTY_OVERRIDES += ro.surface_flinger.primary_display_orientation=ORIENTATION_270
else
PRODUCT_PROPERTY_OVERRIDES += ro.surface_flinger.primary_display_orientation=ORIENTATION_0
endif
endif
不难发现 primary_display_orientation 值由宏定义 决定
MTK_LCM_PHYSICAL_ROTATION = 270
3、关机充电 Logo 方向控制
关机充电 Logo 绘制代码也在 libshowlogo 中
void init_charging_animation_ui_dimension() {
int lcm_width, lcm_height;
struct fb_var_screeninfo vinfo;
display_fd = open("/dev/graphics/fb0", O_RDONLY);
if (display_fd < 0) {
SLOGD("[show_animation_common: %s %d]open mtkfb fail...\n",__FUNCTION__,__LINE__);
}
if (ioctl(display_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
close(display_fd);
SLOGD("[show_animation_common: %s %d]ioctl FBIOGET_VSCREENINFO failed\n",__FUNCTION__,__LINE__);
}
close(display_fd);
lcm_width = vinfo.xres;
lcm_height = vinfo.yres;
int rotation = getRotation();
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]rotation = %d\n",__FUNCTION__,__LINE__, rotation);
}
if ((ORIENTATION_270 == rotation)|| (ORIENTATION_90 == rotation)){
lcm_width = vinfo.yres;
lcm_height = vinfo.xres;
}
SLOGD("[show_animation_common: %s %d] lcm_width and lcm_height= %d , %d \n",__FUNCTION__,__LINE__,lcm_width,lcm_height);
.......
也是根据 int rotation = getRotation(); 来决定旋转角度,和上面的 kernel logo 一样由 决定。
4、开机动画方向控制
开机动画播放代码位置如下
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
if (mDisplayToken == nullptr)
return NAME_NOT_FOUND;
DisplayConfig displayConfig;
const status_t error =
SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &displayConfig);
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 = displayConfig.resolution;
resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::Transaction t;
+ Rect destRect(resolution.getWidth(), resolution.getHeight());
+ t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, destRect, destRect);
// this guest property specifies multi-display IDs to show the boot animation
// multiple ids can be set with comma (,) as separator, for example:
// setprop persist.boot.animation.displays 19260422155234049,19261083906282754
Vector<uint64_t> physicalDisplayIds;
char displayValue[PROPERTY_VALUE_MAX] = "";
property_get(DISPLAYS_PROP_NAME, displayValue, "");
......
播放绘制核心方法为 BootAnimation::readyToRun(),其中可通过 Transaction t 的 displayProjection
来决定方向。 ui::ROTATION_0 ui::ROTATION_90 ui::ROTATION_180 ui::ROTATION_270
这里添加的是 ui::ROTATION_0 为了解决播放动画后半段有一半显示不完整问题。
5、RecoveryUI 方向控制
RecoveryUI 绘制代码位于,
谷歌已经为我们提供了兼容旋转显示
int gr_init() {
......
std::string rotation_str =
android::base::GetProperty("ro.minui.default_rotation", "ROTATION_NONE");
if (rotation_str == "ROTATION_RIGHT") {
gr_rotate(GRRotation::RIGHT);
} else if (rotation_str == "ROTATION_DOWN") {
gr_rotate(GRRotation::DOWN);
} else if (rotation_str == "ROTATION_LEFT") {
gr_rotate(GRRotation::LEFT);
} else {
// "ROTATION_NONE" or unknown string
gr_rotate(GRRotation::NONE);
}
核心方法 gr_init() 中读取 prop ro.minui.default_rotation 值决定绘制方向
搜索后发现并没有定义赋值的地方,那我们就自己加一个赋值为横屏 ROTATION_LEFT
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.minui.default_rotation=ROTATION_LEFT
6、系统 TP 触控 x y 方向控制
核心控制逻辑如下
#ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION
if (strncmp(CONFIG_MTK_LCM_PHYSICAL_ROTATION, "90", 2) == 0
|| strncmp(CONFIG_MTK_LCM_PHYSICAL_ROTATION, "270", 3) == 0) {
#ifdef CONFIG_MTK_FB
/*Fix build errors,as some projects cannot support these apis while bring up*/
TPD_RES_Y = DISP_GetScreenWidth();
TPD_RES_X = DISP_GetScreenHeight();
#endif
} else
#endif
{
static void tpd_down(s32 x, s32 y, s32 size, s32 id)
{
if ((!size) && (!id)) {
input_report_abs(tpd->dev, ABS_MT_PRESSURE, 100);
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 100);
} else {
input_report_abs(tpd->dev, ABS_MT_PRESSURE, size);
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, size);
/* track id Start 0 */
input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, id);
}
input_report_key(tpd->dev, BTN_TOUCH, 1);
#if 0
input_report_abs(tpd->dev, ABS_MT_POSITION_X, x);
input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y);
#else
input_report_abs(tpd->dev, ABS_MT_POSITION_X, 1280-y);
input_report_abs(tpd->dev, ABS_MT_POSITION_Y, x);
#endif
得到由宏定义 决定 x y 坐标
CONFIG_MTK_LCM_PHYSICAL_ROTATION="270"
7、开机默认横屏显示
修改完上面的步骤后开机已经是横屏了,具体和
所决定 ro.surface_flinger.primary_display_orientation 值有关系
核心代码如下
ifneq ($(SF_PRIMARY_DISPLAY_ORIENTATION),)
LOCAL_CFLAGS += -DPRIMARY_DISPLAY_ORIENTATION=$(SF_PRIMARY_DISPLAY_ORIENTATION)
endif
Return<void> SurfaceFlingerConfigs::primaryDisplayOrientation(
primaryDisplayOrientation_cb _hidl_cb) {
using ::android::hardware::configstore::V1_1::DisplayOrientation;
bool specified = false;
DisplayOrientation value = DisplayOrientation::ORIENTATION_0;
int orientation = 0;
#ifdef PRIMARY_DISPLAY_ORIENTATION
specified = true;
orientation = PRIMARY_DISPLAY_ORIENTATION;
#endif
switch (orientation) {
case 0: {
value = DisplayOrientation::ORIENTATION_0;
break;
}
case 90: {
value = DisplayOrientation::ORIENTATION_90;
break;
}
case 180: {
value = DisplayOrientation::ORIENTATION_180;
break;
}
case 270: {
value = DisplayOrientation::ORIENTATION_270;
break;
}
default: {
// statically checked above -> memory corruption
LOG_ALWAYS_FATAL("Invalid orientation %d", orientation);
}
}
_hidl_cb({
specified, value});
return Void();
}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization 标签:
sp2880角度传感器sp2801角度传感器