Android11.0 平板默认横屏且兼容重力传感器方案
发布日期:2021-06-29 13:07:50 浏览次数:2 分类:技术文章

本文共 19360 字,大约阅读时间需要 64 分钟。

前言

之前搞过的默认横屏大都都是强制性的,静止了自动旋转,那是因为本身也不带重力传感器。之前的改法过于暴力不太正统,

这次仔细研究了下 android 横竖屏控制相关的代码,整理了一套合适的修改方案。

大多情况下竖屏横用是常见的应用场景,这样做应该能节省成本,但给系统软件带来的麻烦不小。

而在安卓版本的迭代中,谷歌和 MTK 已经将屏幕旋转这块做的很完善了, 这里就以 MTK 平台 android11 最新源码分析。

1、Uboot Logo(开机第一屏)方向控制

MTK 的 UbootLogo 绘制在 lk 代码中,算是比较完善的框架了,不管版本怎么迭代,几乎没怎么变动。

代码路径如下

vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6765\mt_logo.c

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(),其中根据 MTK_LCM_PHYSICAL_ROTATION 来设置 ubootlogo 旋转角度,说明 MTK 已经做好了兼容

我们只需找到 MTK_LCM_PHYSICAL_ROTATION 配置为想要的方向角度即可。

经过搜索在 project/$(PROJECT).mk 中找到定义

alps\vendor\mediatek\proprietary\bootable\bootloader\lk\project\k62v1_64_bsp.mk

MTK_LCM_PHYSICAL_ROTATION = 270

lk 的编译规则定义在 alps\vendor\mediatek\proprietary\bootable\bootloader\lk\makefile

include project/$(PROJECT).mkinclude make/rat_config.mkinclude target/$(TARGET)/rules.mkinclude dev/rules.mkinclude platform/$(PLATFORM)/rules.mkifeq ($(MTK_EMMC_SUPPORT), yes)

2、Kernel Logo(开机第二屏)方向控制

KernelLogo 的绘制在 libshowlogo 库中,调用 show_kernel_logo()

alps\vendor\mediatek\proprietary\external\charger\bootlogo.cpp

void bootlogo_show_kernel(){
KPOC_LOGI("[ChargingAnimation: %s %d] show kernel logo \n",__FUNCTION__,__LINE__); show_kernel_logo();}

alps\vendor\mediatek\proprietary\external\libshowlogo\charging_animation.cpp

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() 实现方法位于

alps\vendor\mediatek\proprietary\external\libshowlogo\utils.cpp

#include "utils.h"#include 
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 对应值,继续寻找在哪里赋值

位于 alps\device\mediatek\common\device.mk

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  endifendif

不难发现 primary_display_orientation 值由宏定义 MTK_LCM_PHYSICAL_ROTATION 决定

alps\device\mediateksample\k62v1_64_bsp\ProjectConfig.mk

MTK_LCM_PHYSICAL_ROTATION = 270

3、关机充电 Logo 方向控制

关机充电 Logo 绘制代码也在 libshowlogo 中

alps\vendor\mediatek\proprietary\external\libshowlogo\show_animation_common.c

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 一样由 MTK_LCM_PHYSICAL_ROTATION 决定。

4、开机动画方向控制

开机动画播放代码位置如下

alps\frameworks\base\cmds\bootanimation\BootAnimation.cpp

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
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
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 绘制代码位于,alps\bootable\recovery\minui\graphics.cpp

谷歌已经为我们提供了兼容旋转显示

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

alps\device\mediateksample\k62v1_64_bsp\device.mk

PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.minui.default_rotation=ROTATION_LEFT

6、系统 TP 触控 x y 方向控制

核心控制逻辑如下

alps\kernel-4.19\drivers\input\touchscreen\mtk_tpd.c

#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 {

alps\kernel-4.19\drivers\input\touchscreen\GT911\gt9xx_driver.c

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

得到由宏定义 CONFIG_MTK_LCM_PHYSICAL_ROTATION 决定 x y 坐标

alps\kernel-4.19\arch\arm64\configs\k62v1_64_bsp_defconfig

CONFIG_MTK_LCM_PHYSICAL_ROTATION="270"

7、开机默认横屏显示

修改完上面的步骤后开机已经是横屏了,具体和 MTK_LCM_PHYSICAL_ROTATION

所决定 ro.surface_flinger.primary_display_orientation 值有关系

核心代码如下

alps\hardware\interfaces\configstore\1.1\default\surfaceflinger.mk

ifneq ($(SF_PRIMARY_DISPLAY_ORIENTATION),)    LOCAL_CFLAGS += -DPRIMARY_DISPLAY_ORIENTATION=$(SF_PRIMARY_DISPLAY_ORIENTATION)endif

alps\hardware\interfaces\configstore\1.1\default\SurfaceFlingerConfigs.cpp

Return
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();}

alps\frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting"); hasSyncFramework = running_without_sync_framework(true); ...... wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace; defaultCompositionPixelFormat = static_cast
( default_composition_pixel_format(ui::PixelFormat::RGBA_8888)); wideColorGamutCompositionPixelFormat = static_cast
(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); mColorSpaceAgnosticDataspace = static_cast
(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); useContextPriority = use_context_priority(true); using Values = SurfaceFlingerProperties::primary_display_orientation_values; switch (primary_display_orientation(Values::ORIENTATION_0)) {
case Values::ORIENTATION_0: break; case Values::ORIENTATION_90: internalDisplayOrientation = ui::ROTATION_90; break; case Values::ORIENTATION_180: internalDisplayOrientation = ui::ROTATION_180; break; case Values::ORIENTATION_270: internalDisplayOrientation = ui::ROTATION_270; break; } ALOGV("Internal Display Orientation: %s", toCString(internalDisplayOrientation)); mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries(); // debugging stuff... char value[PROPERTY_VALUE_MAX]; property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value);

alps\frameworks\native\services\surfaceflinger\SurfaceFlingerProperties.cpp

SurfaceFlingerProperties::primary_display_orientation_values primary_display_orientation(        SurfaceFlingerProperties::primary_display_orientation_values defaultValue) {
auto temp = SurfaceFlingerProperties::primary_display_orientation(); if (temp.has_value()) {
return *temp; } auto configDefault = DisplayOrientation::ORIENTATION_0; switch (defaultValue) {
case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90: configDefault = DisplayOrientation::ORIENTATION_90; break; case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180: configDefault = DisplayOrientation::ORIENTATION_180; break; case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270: configDefault = DisplayOrientation::ORIENTATION_270; break; default: configDefault = DisplayOrientation::ORIENTATION_0; break; } DisplayOrientation result = getDisplayOrientation
( configDefault); switch (result) {
case DisplayOrientation::ORIENTATION_90: return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90; case DisplayOrientation::ORIENTATION_180: return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180; case DisplayOrientation::ORIENTATION_270: return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270; default: break; } return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0;}

8、重力传感器驱动调试

参考这篇

9、默认横屏兼容重力传感器自动旋转

打开系统自动旋转功能按钮,屏幕可跟随当前方向旋转显示

关闭系统自动旋转功能按钮,强制所有 APP 默认横屏显示,不管 portrait 属性

alps\frameworks\base\services\core\java\com\android\server\wm\DisplayRotation.java

@Override       boolean updateRotationUnchecked(boolean forceUpdate) {
//add int flag = android.provider.Settings.System.getInt(mContext.getContentResolver(), "accelerometer_rotation", 0); if (flag == 0) {
return true; }//end final int displayId = mDisplayContent.getDisplayId(); if (!forceUpdate) {
if (mDeferredRotationPauseCount > 0) {
// Rotation updates have been paused temporarily. Defer the update until updates // have been resumed. ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused."); return false; }

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

@ScreenOrientation    @Override    int getOrientation() {
//add int flag = android.provider.Settings.System.getInt(mContext.getContentResolver(), "accelerometer_rotation", 0); if (flag == 0) {
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; }//end mLastOrientationSource = null; if (mIgnoreRotationForApps) {
return SCREEN_ORIENTATION_USER; } if (mWmService.mDisplayFrozen) {
if (mWmService.mPolicy.isKeyguardLocked()) {
// Use the last orientation the while the display is frozen with the keyguard // locked. This could be the keyguard forced orientation or from a SHOW_WHEN_LOCKED // window. We don't want to check the show when locked window directly though as // things aren't stable while the display is frozen, for example the window could be // momentarily unavailable due to activity relaunch. ProtoLog.v(WM_DEBUG_ORIENTATION, "Display id=%d is frozen while keyguard locked, return %d", mDisplayId, getLastOrientation()); return getLastOrientation(); } } final int rootOrientation = mRootDisplayArea.getOrientation(); mLastOrientationSource = mRootDisplayArea.getLastOrientationSource(); return rootOrientation; }

10、参考资料

转载地址:https://cczheng.blog.csdn.net/article/details/117751725 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android11.0 V-A/B无缝OTA升级update_engine
下一篇:Android 屏幕显示方向分析

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月25日 04时08分56秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章