欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-11-14 17:53:28
文章较长建议先收藏再看 拆解步骤 1、app 强制横屏显示,无视 android:screenOrientation="portrait" 属性 2、屏幕触摸坐标修改为横屏 3、开机动画横屏 4、开机logo、关机充电动画横屏 5、RecoveryUI 横屏 上代码 1、app 强制横屏显示 修改 ......

文章较长建议先收藏再看

拆解步骤

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

displaycontent 显示 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 中已经是横屏的图片

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

则我们将 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 的布局显示

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

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,这样就大功告成了,完美的横屏适配

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