Android9.0 MTK 平板横屏方案修改(强制app横屏 + 开机logo/动画+关机充电横屏 + RecoveryUI 横屏)

简介: Android9.0 MTK 平板横屏方案修改(强制app横屏 + 开机logo/动画+关机充电横屏 + RecoveryUI 横屏)

文章较长建议先收藏再看


拆解步骤


1、app 强制横屏显示,无视 android:screenOrientation=“portrait” 属性

2、屏幕触摸坐标修改为横屏

3、开机动画横屏

4、开机logo、关机充电动画横屏

5、RecoveryUI 横屏


上代码


##1、app 强制横屏显示

修改 rotationForOrientationLw(), 默认返回 270

frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java

 @Override
    public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) {
        ....
        synchronized (mLock) {
    ...
    default:
                    // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
                    // just return the preferred orientation we already calculated.
                    if (preferredRotation >= 0) {
                        return preferredRotation;
                    }
                    // return Surface.ROTATION_0;
                    return Surface.ROTATION_270;//cczheng add for land scap
            }
        }
  }

activity 默认强制属性为 SCREEN_ORIENTATION_LANDSCAPE

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

boolean updateOrientationFromAppTokensLocked(int displayId, boolean forceUpdate) {
        long ident = Binder.clearCallingIdentity();
        try {
            final DisplayContent dc = mRoot.getDisplayContent(displayId);
            // final int req = dc.getOrientation();
            int req = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;//cczheng add for land scap
            if (req != dc.getLastOrientation() || forceUpdate) {
                if (DEBUG_ORIENTATION) {
                    Slog.v(TAG, "updateOrientation: req= " + req + ", mLastOrientation= "
                        + dc.getLastOrientation(), new Throwable("updateOrientation"));
                }
                dc.setLastOrientation(req);
                //send a message to Policy indicating orientation change to take
                //action like disabling/enabling sensors etc.,
                // TODO(multi-display): Implement policy for secondary displays.
                if (dc.isDefaultDisplay) {
                    mPolicy.setCurrentOrientationLw(req);
                }
                return dc.updateRotationUnchecked(forceUpdate);
            }
            return false;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

isPlayContent 显示 mRotation 默认改为 3 (270)

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

/**
     * Current rotation of the display.
     * Constants as per {@link android.view.Surface.Rotation}.
     *
     * @see #updateRotationUnchecked()
     */
    // private int mRotation = 0;
    private int mRotation = 3;//cczheng add for land scap

修改默认值 config_reverseDefaultRotation 为 true,翻转显示角度

frameworks\base\core\res\res\values\config.xml

<!-- If true, the direction rotation is applied to get to an application's requested
         orientation is reversed.  Normally, the model is that landscape is
         clockwise from portrait; thus on a portrait device an app requesting
         landscape will cause a clockwise rotation, and on a landscape device an
         app requesting portrait will cause a counter-clockwise rotation.  Setting
         true here reverses that logic. -->
  <!-- cczheng add for land scap -->
    <bool name="config_reverseDefaultRotation">true</bool> 
  <!-- The number of degrees to rotate the display when the keyboard is open.
         A value of -1 means no change in orientation by default. -->
    <!-- cczheng add for land scap -->
    <integer name="config_lidOpenRotation">270</integer>

2、屏幕触摸坐标修改为横屏


对调 frame 的宽和高,设置方向为 270

frameworks\native\services\surfaceflinger\DisplayDevice.cpp

void DisplayDevice::setProjection(int orientation,
        const Rect& newViewport, const Rect& newFrame) {
    Rect viewport(newViewport);
    Rect frame(newFrame);
    const int w = mDisplayWidth;
    const int h = mDisplayHeight;
    Transform R;
    DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
    if (!frame.isValid()) {
        // the destination frame can be invalid if it has never been set,
        // in that case we assume the whole display frame.
        //cczheng add for land scap
        // frame = Rect(w, h);
        if (w < h)
            frame = Rect(h, w);
        else
            frame = Rect(w, h);
    }
  ....
}
// clang-format off
DisplayDevice::DisplayDevice(
        const sp<SurfaceFlinger>& flinger,
        DisplayType type,
        int32_t hwcId,
        bool isSecure,
        const wp<IBinder>& displayToken,
        const sp<ANativeWindow>& nativeWindow,
        const sp<DisplaySurface>& displaySurface,
        std::unique_ptr<RE::Surface> renderSurface,
        int displayWidth,
        int displayHeight,
        bool hasWideColorGamut,
        const HdrCapabilities& hdrCapabilities,
        const int32_t supportedPerFrameMetadata,
        const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
        int initialPowerMode)
      .....
    mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
    // initialize the display orientation transform.
    // setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
    //cczheng add for land scap
    setProjection(DisplayState::eOrientation270, mViewport, mFrame);
#ifdef MTK_SF_DEBUG_SUPPORT
    mFps = FpsCounterLoader::getInstance().create();
#endif
}


frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

void SurfaceFlinger::onInitializeDisplays() {
    // reset screen orientation and use primary layer stack
    Vector<ComposerState> state;
    Vector<DisplayState> displays;
    DisplayState d;
    d.what = DisplayState::eDisplayProjectionChanged |
             DisplayState::eLayerStackChanged;
    d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
    d.layerStack = 0;
    //d.orientation = DisplayState::eOrientationDefault;
    //cczheng add for land scap
    d.orientation = DisplayState::eOrientation270;
    d.frame.makeInvalid();
    d.viewport.makeInvalid();
    d.width = 0;
    d.height = 0;
    displays.add(d);
    ....
}


3、开机动画横屏


对调 createSurface() 的 w 和 h

frameworks\base\cmds\bootanimation\BootAnimation.cpp

status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();
    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    DisplayInfo dinfo;
    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    if (status)
        return -1;
    // create the native surface
    /*sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);*/
    //cczheng add for land scap  [S]
    sp<SurfaceControl> control;
    if(dinfo.w < dinfo.h)
        control = session()->createSurface(String8("BootAnimation"),
            dinfo.h, dinfo.w, PIXEL_FORMAT_RGB_565);
    else
        control = session()->createSurface(String8("BootAnimation"),
            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
    //cczheng add for land scap  [E]
    SurfaceComposerClient::Transaction t;
    t.setLayer(control, 0x40000000)
        .apply();
  .....
}


开机动画制作替换后面补充。。。


4、开机logo、关机充电动画横屏


开机logo定义屏幕分辨率以对应资源文件夹的位置为

vendor\mediatek\proprietary\bootable\bootloader\lk\project\xxxx.mk 没有则看下面的

device\mediateksample\xxxx\ProjectConfig.mk


mk 中的 BOOT_LOGO = wxga


对应的资源文件位置在 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/wxga


可以看到 wxga 中都是竖屏的图片,而 wxganl 中已经是横屏的图片


aHR0cHM6Ly9zMi5heDF4LmNvbS8yMDE5LzEwLzExL3ViV2tOdC5wbmc.png则我们将 BOOT_LOGO 修改为 wxganl 即可


接下来还需要继续修改显示的角度,依旧改成 270,不然会出现花屏的现象


开机第一张图片 uboot 对应显示


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

void init_fb_screen()
{
  .....
  // 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 = 270;//cczheng add for land scap
  }
  ....

开机第二张图片 kernel 对应显示


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

int anim_fb_init(void)
{
     .....
    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);
    }
    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 = 270;//cczheng add for land scap
    }
    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;
}


如果出现充电动画图片错位的现象,多数都是因为图形绘制点和屏幕尺寸不匹配导致的。可通过调整 cust_display.h 中位置参数


Android M 后:/vendor/mediatek/proprietary/external/libshowlogo/cust_display.h


Android M 前: /vendor/mediatek/proprietary/bootable/bootloader/lk/target/${PROJECT}/include/target/cust_display.h


(1 ,使用old version动画方案的调整如下设置,


#define BAR_LEFT (215)

#define BAR_TOP (156)

#define BAR_RIGHT (265)

#define BAR_BOTTOM (278)

可以用windows的画图软件打开第1点里提到的图片,根据电池边框的像素来调整。


这里坐标的参考原点是左上角,背景图片的左上角是(0,0),这四个值都是相对于左上角的坐标来确定的,因此RIGHT > LEFT,BOTTOM > TOP

小技巧:1)打开画图软件,选择 查看->缩放->自定义,将图片放到到800%

2)选择 查看->缩放->显示网格

这样就可以看到一个一个的像素

(2,使用new version动画方案调整如下设置:

#define CAPACITY_LEFT (278) 
#define CAPACITY_TOP (556)
#define CAPACITY_RIGHT (441)
#define CAPACITY_BOTTOM (817)

5、RecoveryUI 横屏


参考之前写的文章 MTK Recovery 模式横屏修改(适用于6.0 + 8.1+9.0)


6、系统导航栏位置调整,横屏后 navigationBarPosition 默认在左边


作为平板项目,需要将位置改为底部,直接修改 navigationBarPosition() 返回 NAV_BAR_BOTTOM


frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java

@NavigationBarPosition
    private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
      //cchzneg annotaion for land scape
        /*if (mNavigationBarCanMove && displayWidth > displayHeight) {
            if (displayRotation == Surface.ROTATION_270) {
                return NAV_BAR_LEFT;
            } else {
                return NAV_BAR_RIGHT;
            }
        }*/
        return NAV_BAR_BOTTOM;
    }

这样位置是变为底部了,但是三个按钮都重叠在一起了,需要修改 SystemUI 的布局显示


20191016151037965.png


vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java

private void updateRotatedViews() {
        //cczheng change rot0 rot90 for landscape
        mRotatedViews[Surface.ROTATION_0] =
                mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot90);
                // mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
        mRotatedViews[Surface.ROTATION_270] =
                mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot0);
                // mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);        
        updateCurrentView();
    }

顺带再调整下 NavigationBarView 的默认高度和左边 Back 键区域太大的问题


vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarInflaterView.java

private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
        View v = null;
        String button = extractButton(buttonSpec);
        if (LEFT.equals(button)) {
             //cchzheng change NAVSPACE to MENU_IME for small left back click area
            String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, MENU_IME_ROTATE/*NAVSPACE*/);
            button = extractButton(s);
        } else if (RIGHT.equals(button)) {
            String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME_ROTATE);
            button = extractButton(s);
        }
    ...


frameworks\base\core\res\res\values\dimens.xml

 <!-- Height of the bottom navigation / system bar. -->
    <!--cczheng change 48dp to 30dp-->
    <dimen name="navigation_bar_height">30dp</dimen>


ok,这样就大功告成了,完美的横屏适配


2019101615110540.png


目录
相关文章
|
2月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
181 0
安卓项目:app注册/登录界面设计
|
2月前
|
Ubuntu Linux Android开发
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
本文介绍了如何在Android设备上安装Termux和AnLinux,并通过这些工具运行Ubuntu系统和桌面环境。
158 2
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
|
2月前
|
前端开发 API Android开发
10 大 APP 开发方案比较
本文首发于微信公众号“前端徐徐”,深入剖析了当前最受欢迎的十种APP开发方案,包括传统的iOS和Android开发、跨平台的React Native和Flutter、现代化的CapacitorJS和PWA等,旨在帮助开发者在众多选择中找到最适合的开发路径。通过详细分析每种方案的优缺点及适用场景,文章提供了详尽的比较和实用建议,助力高效、优质的APP开发。
211 0
10 大 APP 开发方案比较
|
3月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
146 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
3月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
256 2
|
3月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
118 3
|
3月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
89 10
|
2月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
352 0
|
3月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
4月前
|
API Android开发
Android P 性能优化:创建APP进程白名单,杀死白名单之外的进程
本文介绍了在Android P系统中通过创建应用进程白名单并杀死白名单之外的进程来优化性能的方法,包括设置权限、获取运行中的APP列表、配置白名单以及在应用启动时杀死非白名单进程的代码实现。
72 1

热门文章

最新文章