Android9.0 MTK 平板橫屏方案修改(強制app橫屏 + 開機logo/動畫+關機充電橫屏 + RecoveryUI 橫屏)

来源:https://www.cnblogs.com/cczheng-666/archive/2019/10/17/11689854.html
-Advertisement-
Play Games

文章較長建議先收藏再看 拆解步驟 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 中已經是橫屏的圖片

ubWkNt.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 的佈局顯示

在這裡插入圖片描述

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,這樣就大功告成了,完美的橫屏適配

在這裡插入圖片描述


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文翻譯自官網,官網地址:(https://docs.influxdata.com/influxdb/v1.7/query_language/data_exploration/) GROUP BY子句通過用戶自己制定的tags set或time區間,來將查詢結果進行分組。 一、GROUP BY ta ...
  • 本文翻譯自官網,官網地址:(https://docs.influxdata.com/influxdb/v1.7/query_language/data_exploration/) WHERE子句 語法: 註 :在WHERE子句中,支持在fields, tags, and timestamps上進行條 ...
  • 本文翻譯自官網,官方文檔地址:(https://docs.influxdata.com/influxdb/v1.7/query_language/data_exploration/) InfluxQL是用於在InfluxDB中進行數據探索的類似於SQL的查詢語法。下麵將詳細介紹在InfluxDB中使 ...
  • 本文翻譯自官網,官方文檔地址: 1.下載官網示例數據 命令如下: 圖示: 可見,執行完命令之後,在當前目錄可以看到下載成功的數據NOAA_data.txt。通過cat命令還可以看到文件中的內容。 2.將數據導入到influxdb中 命令如下: 圖示: 3.查看結果 進入到InfluxDB中。如下圖, ...
  • 原文鏈接:https://www.cnblogs.com/su-root/p/9689787.html 作 者:小柏 出 處:https://www.cnblogs.com/su-root 關於博主:運維、編程路上的小學生,愛鑽研技術,評論和私信會在第一時間回覆。 版權聲明:本文版權歸作者和博客園共 ...
  • 0x00 基礎操作介紹 在本文中將介紹InfluxDB常用的基礎操作,幫助讀者建立對InfluxDB的感性認識,快速的動手玩起來,持續查詢(Continuous Queies)、Group by、Series、行協議(Line Protocol)、InfluxQL等高級特性和細節,將會在後續文章中逐 ...
  • 修改客戶表 編號為 0101007002,0101007003的樓棟號 007-1-102,007-1-201 UPDATE gas_customerSET building= CASEWHEN govid=380 and customer_no='0101007002' THEN '007-1-1 ...
  • 本文主要對android4.4 RIL的telephony與modem的命令交互流程進行分析,當然本文不是重點介紹telephony。telephony涉及具體業務邏輯內容比較多,包括sim、dail、sms、network等等,以後會針對這些內容學習分析。 RIL在Android體系中的位置: ( ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...