Preface
Most of the default screens you've done before are mandatory, with automatic rotation resting because you don't have a gravity sensor. The previous changes were too violent and less orthodox,
This time, the code related to android horizontal and vertical screen control is carefully studied, and a set of appropriate modifications are arranged.
Vertical screen horizontal is a common application scenario in most cases, which should save costs, but bring a lot of trouble to system software.
In the Android version of the iteration, Google and MTK have already done a good job of rotating the screen, here is the latest source code analysis in MTK platform android11.
1. Uboot Logo direction control
MTK's UbootLogo is drawn in lk code, which is a fairly complete framework. No matter how the version iterates, it hardly changes.
The code path is as follows
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; }
See the core method init_fb_screen(), which is based on MTK_LCM_PHYSICAL_ROTATION to set the ubootlogo rotation angle, MTK is already compatible
We just need to find MTK_ LCM_ PHYSICAL_ The ROTATION configuration is sufficient for the desired orientation angle.
Searched in project/$(PROJECT). Definition found in MK
alps\vendor\mediatek\proprietary\bootable\bootloader\lk\project\k62v1_64_bsp.mk
MTK_LCM_PHYSICAL_ROTATION = 270
Lk's Compilation Rules are defined in alpsvendor\mediatek\proprietary\bootable\bootloader\lk\makefile
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 direction control
Drawing KernelLogo in the libshowlogo library calls 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_before drawing was called FD initialization, the core method is anim_fb_init(void), where int rotation = getRotation();
To set the kernellogo rotation angle, find the getRotation() implementation at
alps\vendor\mediatek\proprietary\external\libshowlogo\utils.cpp
#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; }
Read prop attribute primary_from Display_ Orientation_ Values correspond to values, continue looking for where to assign values
primary_display_orientation_values Definition
Located at 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 endif endif
It is not difficult to find primary_display_orientation value is defined by macro MTK_LCM_PHYSICAL_ROTATION DECISION
alps\device\mediateksample\k62v1_64_bsp\ProjectConfig.mk
MTK_LCM_PHYSICAL_ROTATION = 270
3. Shutdown Charging Logo Direction Control
Shutdown Charge Logo drawing code is also in 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); .......
Also based on int rotation = getRotation(); To determine the rotation angle, as with the kernel logo above, by MTK_LCM_PHYSICAL_ROTATION Decision.
4. Direction control of startup animation
Startup animation playback code location is as follows
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<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, ""); ......
The core method of playback drawing is BootAnimation::readyToRun(), where displayProjection through Transaction is available
To determine the direction. ui::ROTATION_0 ui::ROTATION_90 ui::ROTATION_180 ui::ROTATION_270
Here we add ui::ROTATION_0 To solve the incomplete display of half of the second half of the animation.
5. RecoveryUI direction control
RecoveryUI drawing code is located at alps\bootablerecovery\minui\graphics. CPP
Google has provided us with a compatible rotation display
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); }
Core Method gr_init() reads prop ro.minui.default_rotation value determines drawing direction
After searching, we find that there is no assignment defined, so we add our own assignment to the horizontal ROTATION_LEFT
alps\device\mediateksample\k62v1_64_bsp\device.mk
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.minui.default_rotation=ROTATION_LEFT
6. System TP Touch x y Direction Control
The core control logic is as follows
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
Get CONFIG_defined by macro MTK_ LCM_ PHYSICAL_ ROTATION Determines X-y Coordinates
alps\kernel-4.19\arch\arm64\configs\k62v1_64_bsp_defconfig
CONFIG_MTK_LCM_PHYSICAL_ROTATION="270"
7. Turn on default horizontal display
After modifying the above steps, boot-up is already a horizontal screen, specific and MTK_LCM_PHYSICAL_ROTATION
Decided ro.surface_flinger.primary_display_orientation values are related
The core code is as follows
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<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(); }
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<ui::PixelFormat>( default_composition_pixel_format(ui::PixelFormat::RGBA_8888)); wideColorGamutCompositionPixelFormat = static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); mColorSpaceAgnosticDataspace = static_cast<ui::Dataspace>(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<V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>( 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. Debugging of Gravity Sensor Drive
Refer to this article
MTK 9.0 Platform Debugging gsensor
9. Default horizontal screen compatible gravity sensor auto-rotation
Turn on the system auto-rotation button to rotate the display in the current direction
Turn off the system auto-rotation button to force all APP default horizontal displays, regardless of portrait properties
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; }